我是编程新手,似乎无法找到使程序发现的质数比应有的多6个错误。给定范围的正确答案是904533。
此外,使用的第一个printf似乎不起作用,建议的程序运行时间约为5秒,而我的约为8。
希望有人能帮助我,谢谢您。
#define MINNUM 3990000000
#define MAXNUM 4010000000
#include <stdio.h>
int main()
{
unsigned int r, j, i, checker, k, primecount = 0, d, d_save; //
unsigned int a;
unsigned long long res = 1;
printf("Checking range [3990000000,4010000000] for primes...");
for (k = MINNUM + 1; k <= MAXNUM - 2; k += 2)
{
checker = 0;
if (k % 3 != 0)
{
d = k - 1; // Reset variables
res = 1;
r = 0;
//Create (2^r)*d= n-1
while (d % 2 == 0) {
r++;
d /= 2;
}
//printf("%u can be written as : (2^%d)*%llu\n",k-1,r,d);
d_save = d; //saves d for each j loop
do {
for (j = 1; j <= 3; j++)
{
d = d_save;
res = 1;
if (j == 1) a = 2;
if (j == 2) a = 7;
if (j == 3) a = 61;
//Calculate a^d mod k
while (d > 0)
{
// When y is odd
if (d & 1)
res = (res*a) % k;
// When y is even
d = d >> 1; //Same as y = y/2
a = (a*a) % k;
}
//Miller Rabin's c
if (res == 1 || res == k - 1) { checker = 1; continue; }
while (r != 0)
{
res = (res * res) % k;
if (res == 1) { checker = 0; break; }
if (res == k - 1) { checker = 1; break; }
r--;
}
}
} while (checker == 1);
//printf("check %u %d\n",k,checker);
if (checker == 1) primecount++;
}
}
printf("primes are %u", primecount);
}
答案 0 :(得分:1)
溢出
在3个地方,代码的作用类似于(a*a) % k
。乘法会溢出32位unsigned
数学
替换为(1ULL* a*a) % k
。对于OP代码中使用的值,这不会溢出。
算法的错误应用
OP使用的Miller–Rabin primality test不使用原始的r
是3个j
迭代。
unsigned orignal_r = r; // added
d_save = d; //saves d for each j loop
do {
for (j = 1; j <= 3; j++)
{
r = orignal_r; // added
d = d_save;
默认值为
// checker = 0;
checker = 1;
3不是特殊情况
// if (k % 3 != 0)
if (1)
在while()
之前,将checker设置为false;
checker = 0; // add
while (r != 0)
在while()
之后,测试checker
} // end while (r != 0)
// add
if (checker == 0) {
break;
}
而不是基于checker
进行迭代,而是进行一次迭代。
// } while (checker == 1);
} while (0);
有了这些更改,正确的答案就会出现。
可能还存在其他问题。因此,将素数测试作为函数分离出来的@Antoine Mathys good answer很容易编码,遵循和改进。
限制不明确
循环中的- 2
不清楚。它似乎来自 Miller-Rabin 算法,但这是针对奇数k
和MINNUM
的偶数约束。
// for (k = MINNUM + 1; k <= MAXNUM - 2; k += 2)
// Could use `| 1` to insure `k` starts at odd
for (k = MINNUM | 1; k <= MAXNUM; k += 2)
下面通过一些研究现在很简单
通过另一种算法,计数应为904533。
第一个错误的素数是3991124341。我怀疑确定该错误将解释其他错误。
False prime 3991124341 = 33769 * 118189
False prime 3992697997 = 137 * 3061 * 9521
False prime 3997536427 = 19267 * 207481
False prime 3999921383 = 18787 * 212909
False prime 4002510817 = 223 * 2887 * 6217
False prime 4002592133 = 36527 * 109579
答案 1 :(得分:0)
我不会给您完整的代码,您将需要做一些工作以填补空白。
首先,如果您有这样的事情
unsigned int a, b, c, d;
a = (b * c) % k;
替换为
unsigned int a, b, c, d;
a = (1ULL * b * c) % k;
功能是您的朋友。您可以像这样构造整个程序:
#include <stdio.h>
#include <stdbool.h>
#define MINNUM 3990000000U
#define MAXNUM 4010000000U
// calculate a^d mod k
unsigned int exp_mod (unsigned int a, unsigned int d, unsigned int k)
{
...
}
// assume 1 < k < 4759123141
// assume k odd
bool is_prime (unsigned int k)
{
// calculate d and r such that k - 1 = (2^r) * d, with d odd
unsigned int d, r;
...
const unsigned int a[3] = { 2, 7, 61 };
for (int j = 0; j < 3; j++) {
if (k == a[j]) {
return true;
}
unsigned int res = exp_mod (a[j], d, k);
if (res == 1 || res == (k - 1)) {
continue;
}
bool composite = true;
for (unsigned int s = 1; s < r; s++) {
res = (1ULL * res * res) % k;
if (res == k - 1) {
composite = false;
break;
}
}
if (composite) {
return false;
}
}
return true;
}
int main ()
{
...
}