质数查找器,发现质数比应有的多6个

时间:2018-11-17 09:14:10

标签: c

我是编程新手,似乎无法找到使程序发现的质数比应有的多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);
}

2 个答案:

答案 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 算法,但这是针对奇数kMINNUM的偶数约束。

// 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 ()
{
    ...
}