【问题标题】:Miller-Rabin primality test issue in C++C++ 中的 Miller-Rabin 素数测试问题
【发布时间】:2012-09-14 20:21:08
【问题描述】:

我一直在尝试实现 the algorithm from wikipedia,虽然它从不将合数输出为素数,但它会将 75% 的素数输出为合数。

最多 1000 它给了我这个素数输出:

3、5、7、11、13、17、41、97、193、257、641、769

据我所知,我的实现与伪代码算法完全相同。我已经逐行调试它,它产生了所有预期的变量值(我跟着我的计算器)。这是我的功能:

bool primeTest(int n)
{
    int s = 0;
    int d = n - 1;

    while (d % 2 == 0)
    {
        d /= 2;
        s++;
    }

    // this is the LOOP from the pseudo-algorithm
    for (int i = 0; i < 10; i++)
    {
        int range = n - 4;
        int a = rand() % range + 2;
        //int a = rand() % (n/2 - 2) + 2;
        bool skip = false;
        long x = long(pow(a, d)) % n;

        if (x == 1 || x == n - 1)
            continue;

        for (int r = 1; r < s; r++)
        {
            x = long(pow(x, 2)) % n;

            if (x == 1)
            {
                // is not prime
                return false;
            }
            else if (x == n - 1)
            {
                skip = true;
                break;
            }
        }

        if (!skip)
        {
            // is not prime
            return false;
        }
    }

    // is prime
    return true;
}

任何帮助将不胜感激 D:

编辑:这是整个程序,按照你们的建议进行了编辑 - 现在输出更糟糕了:

bool primeTest(int n);

int main()
{
    int count = 1;     // number of found primes, 2 being the first of course
    int maxCount = 10001;
    long n = 3;
    long maxN = 1000;
    long prime = 0;

    while (count < maxCount && n <= maxN)
    {
        if (primeTest(n))
        {
            prime = n;
            cout << prime << endl;
            count++;
        }

        n += 2;
    }

    //cout << prime;
    return 0;
}

bool primeTest(int n)
{
    int s = 0;
    int d = n - 1;

    while (d % 2 == 0)
    {
        d /= 2;
        s++;
    }

    for (int i = 0; i < 10; i++)
    {
        int range = n - 4;
        int a = rand() % range + 2;
        //int a = rand() % (n/2 - 2) + 2;
        bool skip = false;
        //long x = long(pow(a, d)) % n;
        long x = a;
        for (int z = 1; z < d; z++)
        {
            x *= x;
        }

        x = x % n;

        if (x == 1 || x == n - 1)
            continue;

        for (int r = 1; r < s; r++)
        {
            //x = long(pow(x, 2)) % n;
            x = (x * x) % n;

            if (x == 1)
            {
                return false;
            }
            else if (x == n - 1)
            {
                skip = true;
                break;
            }
        }

        if (!skip)
        {
            return false;
        }
    }

    return true;
}

现在素数的输出,从 3 到 1000(和以前一样)是:

3、5、17、257

我现在看到 x 变得太大了,它只是变成了一个垃圾值,但直到我删除了 "%n" 部分我才看到。

【问题讨论】:

  • 你检查过 pow(a, d) 是否溢出?或者如果整数 > 17 存在舍入误差?
  • 它在这里工作。您确定打印正确吗?

标签: c++ math primes


【解决方案1】:

错误的可能来源是对 pow 函数的两次调用。中间结果会很大(尤其是第一次调用)并且可能会溢出,导致错误。您应该查看 Wikipedia 上的 modular exponentiation 主题。

【讨论】:

    【解决方案2】:

    问题的根源可能在这里:

    x = long(pow(x, 2)) % n;
    

    C 标准库中的pow 处理浮点数,因此如果您只想计算以 n 为模的幂,那么使用它是一个非常糟糕的主意。解法其实很简单,用手算个数就行了:

    x = (x * x) % n
    

    【讨论】:

    • +1,虽然可能值得注意的是,他应该对 long x = long(pow(a, d)) % n; 做同样的事情,当然只是略有不同:)
    • 也许他应该使用 GMP 库,而不是仅仅从维基百科复制/粘贴一些伪代码。 GMP 已经内置了 Miller-Rabin 的实现,但他也可以使用 GMP 数据类型自己实现它,它不会像 int 或 long 那样溢出......
    猜你喜欢
    • 2016-02-27
    • 2013-06-09
    • 1970-01-01
    • 2019-10-04
    • 1970-01-01
    • 2021-07-05
    • 2016-10-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多