Miller–Rabin primality test

本文介绍了一个由Christian Stigen Larsen实现的米勒-拉宾素性测试算法,该算法是一种概率性的素数判定方法。文章包含了完整的C语言实现代码,详细解释了算法原理及其实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://github.com/cslarsen/miller-rabin/blob/master/miller-rabin.cpp


/*
* The Miller-Rabin primality test
*
* Written by Christian Stigen Larsen, 2012-01-10
* http://csl.sublevel3.org
*
* Distributed under the modified BSD license
*
* NOTE: I implemented this probabilistic algorithm purely as a recreational
* challenge. The code has big room for improvements, but it does work
* as advertised.
*/
#include <stdlib.h> // rand
#include <stdint.h> // uint64_t
#include "miller-rabin.h"
/*
* Which PRNG function to use; libc rand() by default
*/
static int (*rand_func)(void) = rand;
/*
* Maximum number that rand_func can return.
*/
static int rand_max = RAND_MAX;
/*
* Fast calculation of `a^x mod n´ by using right-to-left
* binary modular exponentiation.
*
* This algorithm is taken from Bruce Schneier's book
* APPLIED CRYPTOGRAPHY.
*
* See http://en.wikipedia.org/wiki/Modular_exponentiation
*/
static uint64_t pow_mod(uint64_t a, uint64_t x, uint64_t n)
{
  /*
* Note that this code is sensitive to overflowing for testing
* of large prime numbers. The `a*r´ and `a*a´ operations can
* overflow. One easy way of solving this is to use 128-bit
* precision for calculating a*b % n, since the mod operator
* should always get us back to 64bits again.
*
* You can either use GCC's built-in __int128_t or use
*
* typedef unsigned int uint128_t __attribute__((mode(TI)));
*
* to create a 128-bit datatype.
*/
  uint64_t r=1;
  while ( x ) {
    if ( (x & 1) == 1 )
      //r = (__int128_t)a*r % n; // Slow
      r = a*r % n;
    x >>= 1;
    //a = (__int128_t)a*a % n; // SLow
    a = a*a % n;
  }
  return r;
}
/*
* Return an integer between a and b.
*
* Note that we use rand() here, meaning that all its pathological cases
* will apply here as well --- i.e., it's slow and not very random --- but
* should suffice.
*
*/
static uint64_t rand_between(uint64_t a, uint64_t b)
{
  // Assume rand_func() is 32 bits
  uint64_t r = (static_cast<uint64_t>(rand_func())<<32) | rand_func();
  return a + (uint64_t)((double)(b-a+1)*r/(UINT64_MAX+1.0));
}
/*
* The Miller-Rabin probabilistic primality test.
*
* Returns true if ``n´´ is PROBABLY prime, false if it's composite.
* The parameter ``k´´ is the accuracy.
*
* The running time should be somewhere around O(k log_3 n).
*
*/
bool isprime(uint64_t n, int k)
{
  // Must have ODD n greater than THREE
  if ( n==2 || n==3 ) return true;
  if ( n<=1 || !(n & 1) ) return false;
  // Write n-1 as d*2^s by factoring powers of 2 from n-1
  int s = 0;
  for ( uint64_t m = n-1; !(m & 1); ++s, m >>= 1 )
    ; // loop
  uint64_t d = (n-1) / (1<<s);
  for ( int i = 0; i < k; ++i ) {
    uint64_t a = rand_between(2, n-2);
    uint64_t x = pow_mod(a,d,n);
    if ( x == 1 || x == n-1 )
      continue;
    for ( int r = 1; r <= s-1; ++r ) {
      x = pow_mod(x, 2, n);
      if ( x == 1 ) return false;
      if ( x == n - 1 ) goto LOOP;
    }
    return false;
LOOP:
    continue;
  }
  // n is *probably* prime
  return true;
}
/*
* Set which rand function to use.
*
* If passed a NULL parameter, it will revert back to the default libc
* rand().
*/
void setrand(int (*pf)(void), const int rmax)
{
  if ( pf != NULL ) {
    rand_func = pf;
    rand_max = rmax;
  } else {
    rand_func = rand;
    rand_max = RAND_MAX;
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值