Miller Rabin Primality test accuracy

前端 未结 5 918
情深已故
情深已故 2021-01-01 01:52

I know the Miller–Rabin primality test is probabilistic. However I want to use it for a programming task that leaves no room for error.

Can we assume that it is corr

5条回答
  •  醉梦人生
    2021-01-01 02:30

    There are efficient deterministic variants of the MR test for 64-bit values - which do not rely on the GRH - having been exhaustively tested by exploiting GPUs and other known results.

    I've listed the pertinent sections of a C program I wrote that tests the primality of any 64-bit value: (n > 1), using Jaeschke's and Sinclair's bases for the deterministic MR variant. It makes use of gcc and clang's __int128 extended type for exponentiation. If not available, an explicit routine is required. Maybe others will find this useful...

    #include 
    
    /******************************************************************************/
    
    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. */
    }
    
    /******************************************************************************/
    

    Note that the MR (sprp) test is slightly modified to pass values on an iteration where the base is a multiple of the candidate, as mentioned in the 'remarks' section of the website


    Update: while this has fewer base tests than Niklas' answer, it's important to note that the bases: {3, 5, 7, 11, 13, 17, 19, 23, 29} provide a cheap test that allows us to eliminate candidates exceeding: 29 * 29 = 841 - simply using the GCD.

    For (n > 29 * 29), we can clearly eliminate any even value as prime. The product of the small primes: (3 * 5 * 7 * 11 * 13 * 17 * 19 * 23 * 29} = 3234846615, fits nicely in a 32-bit unsigned value. A gcd(n, 3234846615) is a lot cheaper than a MR test! If the result is not (1), then (n) > 841 has a small factor.

    Merten's (?) theorem suggests that this simple gcd(u64, u64) test eliminates ~ 68% of all odd candidates (as composites). If you're using M-R to search for primes (randomly or incrementally), rather than just a 'one-off' test, this is certainly worth while!

提交回复
热议问题