【问题标题】:Miller-Rabin Primality test FIPS 186-3 implementationMiller-Rabin Primality 测试 FIPS 186-3 实施
【发布时间】:2012-06-29 12:11:09
【问题描述】:

我正在尝试根据FIPS 186-3 C.3.1 中的描述来实施 Miller-Rabin 素数测试。无论我做什么,我都无法让它发挥作用。说明非常具体,我认为我没有遗漏任何内容,但我得到了true 的非主要值。

我做错了什么?

template <typename R, typename S, typename T>
T POW(R base, S exponent, const T mod){
    T result = 1;
    while (exponent){
        if (exponent & 1)
            result = (result * base) % mod;
        exponent >>= 1;
        base = (base * base) % mod;
    }
    return result;
}



// used uint64_t to prevent overflow, but only testing with small numbers for now
bool MillerRabin_FIPS186(uint64_t w, unsigned int iterations = 50){
    srand(time(0));
    unsigned int a = 0;
    uint64_t W = w - 1; // dont want to keep calculating w - 1
    uint64_t m = W;
    while (!(m & 1)){
        m >>= 1;
        a++;
    }

    // skipped getting wlen
    // when i had this function using my custom arbitrary precision integer class,
    // and could get len(w), getting it and using it in an actual RBG 
    // made no difference 

    for(unsigned int i = 0; i < iterations; i++){
        uint64_t b = (rand() % (W - 3)) + 2; // 2 <= b <= w - 2
        uint64_t z = POW(b, m, w);
        if ((z == 1) || (z == W))
            continue;
        else
            for(unsigned int j = 1; j < a; j++){
                z = POW(z, 2, w);
                if (z == W)
                    continue;
                if (z == 1)
                    return 0;// Composite
            }
    }
    return 1;// Probably Prime
}

这个:

std::cout << MillerRabin_FIPS186(33) << std::endl;
std::cout << MillerRabin_FIPS186(35) << std::endl;
std::cout << MillerRabin_FIPS186(37) << std::endl;
std::cout << MillerRabin_FIPS186(39) << std::endl;
std::cout << MillerRabin_FIPS186(45) << std::endl;
std::cout << MillerRabin_FIPS186(49) << std::endl;

给我:

0
1
1
1
0
1

【问题讨论】:

  • 我们能看到POW吗?我看到了一个错误,它可以将一些素数声明为复合素数,但反过来却什么也没有。对于哪些值,您得到了错误的结果?
  • 你对战俘的定义在哪里?
  • pow 很好,但无论如何都不能放好
  • 顺便说一句,你的随机数是not uniformly distributed——模运算会扭曲结果。
  • 如果result * basebase * base 溢出会怎样?

标签: c++ math implementation primality-test


【解决方案1】:

您的实现与维基百科的唯一区别是您忘记了第二个返回复合语句。您应该在循环结束时返回 0。

编辑:正如丹尼尔所指出的,还有第二个区别。 continue 是继续内循环,而不是像它应该的外循环。

for(unsigned int i = 0; i < iterations; i++){
    uint64_t b = (rand() % (W - 3)) + 2; // 2 <= b <= w - 2
    uint64_t z = POW(b, m, w);
    if ((z == 1) || (z == W))
        continue;
    else{
        int continueOuter = 0;
        for(unsigned int j = 1; j < a; j++){
            z = POW(z, 2, w);
            if (z == W)
                continueOuter = 1;
                break;
            if (z == 1)
                return 0;// Composite
        }
        if (continueOuter) {continue;}
    }
    return 0; //This is the line you're missing.
}
return 1;// Probably Prime

另外,如果输入是偶数,它可能总是返回素数,因为 a 为 0。您应该在开始时添加一个额外的检查。

【讨论】:

  • 希望素数测试不用于偶数。 :)
  • 哦,拜托,这当然不值得downvote...这是一个好点。 :)
  • 为什么投反对票?这是一个合法的问题,在我写这篇文章时我不知道正在测试哪些数字。
  • 现在我得到 0 0 0 0 0 0 并且我将 {} 添加到 else 中,所以在 1 次迭代后它不会返回 0
  • @calccrypto:你不能只添加break return 0,因为现在只要你break return 0就会被触发。在循环之前将标志(比如 contloop)设置为 false。而不是仅仅中断,设置“contloop = 1; break;},然后仅在 contloop 为 false 时返回 0。[或其他东西。]
【解决方案2】:

在内循环中,

        for(unsigned int j = 1; j < a; j++){
            z = POW(z, 2, w);
            if (z == W)
                continue;
            if (z == 1)
                return 0;// Composite
        }

z == W 时,你应该break; 而不是continue;。通过continueing,在该循环的下一次迭代中,如果有一个,z 将变为 1,并且候选者可能被错误地声明为复合。在这里,这发生在小于 100 的素数中的 17、41、73、89 和 97。

【讨论】:

  • 啊,我也正要点击发送。我认为这和如果这个循环一直通过,则返回 0 都是必要的。
  • 哇,我不敢相信我错过了。 continue 只是继续内部循环,而不是应该的外部循环。
猜你喜欢
  • 1970-01-01
  • 2016-06-12
  • 1970-01-01
  • 2019-10-04
  • 2013-06-08
  • 2016-02-27
  • 2013-06-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多