C 米勒-拉宾素性检验精度

C 米勒-拉宾素性检验精度,c,algorithm,cryptography,primes,primality-test,C,Algorithm,Cryptography,Primes,Primality Test,我知道这是概率性的。然而,我想用它来做一个不留任何错误余地的测试 如果输入的数字是64位整数(即C中的long),我们是否可以假设它是正确的,概率非常高?在Miller-Rabin的每次迭代中,您需要选择一个随机数。如果你运气不好,这个随机数不会显示某些复合物。一个小例子是2^341 mod 341=2,通过了测试 但该测试保证它只允许概率Miller的组合通过–Rabin确实是概率的,但您可以任意用精度换取计算时间。如果你测试的数字是素数,它总是给出正确的答案。有问题的情况是当一个数字是复合的

我知道这是概率性的。然而,我想用它来做一个不留任何错误余地的测试


如果输入的数字是64位整数(即C中的
long
),我们是否可以假设它是正确的,概率非常高?

在Miller-Rabin的每次迭代中,您需要选择一个随机数。如果你运气不好,这个随机数不会显示某些复合物。一个小例子是
2^341 mod 341=2
,通过了测试


但该测试保证它只允许概率Miller的组合通过–Rabin确实是概率的,但您可以任意用精度换取计算时间。如果你测试的数字是素数,它总是给出正确的答案。有问题的情况是当一个数字是复合的,但被报告为素数时。我们可以使用以下公式来限制此错误的概率:如果随机选择
k
不同的基并对其进行测试,则错误概率小于4-k。因此,即使使用
k=9
,你也只有百万分之三的可能出错。当k=40左右时,这种可能性就变得不可思议了

这就是说,依赖于广义黎曼假设的正确性,存在着一个问题。对于范围u 对于264,检查a=2、3、5、7、11、13、17、19、23就足够了。在许多编程竞赛中进行了现场测试。下面是无符号64位整数模板的一个实例:

bool isprime(uint64_t n) { //determines if n is a prime number
    const int pn = 9, p[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23 };
    for (int i = 0; i < pn; ++i)
        if (n % p[i] == 0) return n == p[i];
    if (n < p[pn - 1]) return 0;
    uint64_t s = 0, t = n - 1;
    while (~t & 1)
        t >>= 1, ++s;
    for (int i = 0; i < pn; ++i) {
        uint64_t pt = PowerMod(p[i], t, n);
        if (pt == 1) continue;
        bool ok = 0;
        for (int j = 0; j < s && !ok; ++j) {
            if (pt == n - 1) ok = 1;
            pt = MultiplyMod(pt, pt, n);
        }
        if (!ok) return 0;
    }
    return 1;
}
bool isprime(uint64\u t n){//确定n是否为素数
常数int pn=9,p[]={2,3,5,7,11,13,17,19,23};
对于(int i=0;i>=1,++s;
对于(int i=0;i
PowerMod
MultiplyMod
只是在给定模下使用平方和{multiply,add}进行乘法和幂运算的基本体。

对于n<2^64,可以对七个基2、325、9375、28178、450775、9780504和1795265022执行强伪素数测试,并完全确定n的素数;看

更快的素性测试对基2执行强伪素数测试,然后执行Lucas伪素数测试。它的时间大约是单个强伪素数测试的3倍,因此速度是7基Miller-Rabin测试的两倍多。代码更复杂,但并不可怕


如果你感兴趣,我可以发布代码;请在评论中告诉我。

你的电脑不完美;它失败的概率有限,导致计算结果不正确。假设M-R测试给出错误结果的概率大大低于其他计算机故障的概率,那么您就没事了。没有理由运行M-R测试的迭代次数少于64次(错误概率为1/2^128)。大多数例子在最初的几次迭代中都会失败,所以只有实际的素数会被彻底测试。对于1/2^256的错误概率,使用128次迭代。

64位值的MR测试是有效的,它不依赖GRH,已经通过利用GPU和其他已知结果进行了详尽的测试

我已经列出了我编写的一个C程序的相关部分,该程序测试任何64位值的素性:
(n>1)
,使用Jaeschke和Sinclair的基作为确定性MR变量。它使用gcc和clang的
\uu int128
扩展类型进行求幂。如果不可用,则需要显式例程。也许其他人会发现这很有用

#include <inttypes.h>

/******************************************************************************/

static int sprp (uint64_t n, uint64_t a)
{
    uint64_t m = n - 1, r, y;
    unsigned int s = 1, j;

    /* assert(n > 2 && (n & 0x1) != 0); */

    while ((m & (UINT64_C(1) << s)) == 0) s++;
    r = m >> s; /* r, s s.t. 2^s * r = n - 1, r in odd. */

    if ((a %= n) == 0) /* else (0 < a < n) */
        return (1);

    {
        unsigned __int128 u = 1, w = a;

        while (r != 0)
        {
            if ((r & 0x1) != 0)
                u = (u * w) % n; /* (mul-rdx) */

            if ((r >>= 1) != 0)
                w = (w * w) % n; /* (sqr-rdx) */
        }

        if ((y = (uint64_t) u) == 1)
            return (1);
    }

    for (j = 1; j < s && y != m; j++)
    {
        unsigned __int128 u = y;
        u = (u * u) % n; /* (sqr-rdx) */

        if ((y = (uint64_t) u) <= 1) /* (n) is composite: */
            return (0);
    }

    return (y == m);
}

/******************************************************************************/

static int is_prime (uint64_t n)
{
    const uint32_t sprp32_base[] = /* (Jaeschke) */ {
        2, 7, 61, 0};

    const uint32_t sprp64_base[] = /* (Sinclair) */ {
        2, 325, 9375, 28178, 450775, 9780504, 1795265022, 0};

    const uint32_t *sprp_base;

    /* assert(n > 1); */

    if ((n & 0x1) == 0) /* even: */
        return (n == 2);

    sprp_base = (n <= UINT32_MAX) ? sprp32_base : sprp64_base;

    for (; *sprp_base != 0; sprp_base++)
        if (!sprp(n, *sprp_base)) return (0);

    return (1); /* prime. */
}

/******************************************************************************/
#包括
/******************************************************************************/
静态整数存储过程(uint64\u t n,uint64\u t a)
{
uint64_t m=n-1,r,y;
无符号整数s=1,j;
/*断言(n>2&(n&0x1)!=0)*/
而((m&(UINT64_C(1)>s;/*r,s.t.2^s*r=n-1,r为奇数)*/
如果((a%=n)==0)/*else(0>=1)!=0)
w=(w*w)%n;/*(sqr rdx)*/
}
如果((y=(uint64_t)u)==1)
申报表(1);
}
对于(j=1;jsprp_基=(n你能在这里引用这个算法吗?而且,链接到维基百科会很好。然后我会认为这是一个很好的答案。”JordValk MalkDead不接受维基百科链接中的短线。谢谢@ CODESSIN混沌,至少你回答了!模板是什么?问题是标签C?引用/推理?@ CaskTythUnIUTU只是当作伪代码。LAS几乎不能在这里发布一个大整数库。很明显,<代码> PowerMod < /C>和 MulyYMOD是,但是实现它们是很烦人的,并且对算法的理解没有帮助。@ CyrsiGangUpUITU是从工作实现复制的C++代码,但是您应该能够通过RePL手动实例化模板。通过
uint64\u T
unsigned long long
来计算每次出现的T。此外,
MultiplyMod
PowerMod
的实现也可以在完整的源文件中查找,在我看来,
long long
被定义为具有最小64位。对我来说,这组基础适用于所有人n<2^32,但在n=4033和n=4681时失败,因为