zoukankan      html  css  js  c++  java
  • MillerRabin素数测试学习笔记

      好几天前看了算导上的Miller-Rabin素数测试算法,今天正好总结一下,写写笔记。

      说Miller-Rabin测试以前先说两个比较高效的求a*b% n 和 ab %n 的函数,这里都是用到二进制思想,将b拆分成二进制,然后与a相加(相乘)

    // a * b % n
    //例如: b = 1011101那么a * b mod n = (a * 1000000 mod n + a * 10000 mod n + a * 1000 mod n + a * 100 mod n + a * 1 mod n) mod n

    ll mod_mul(ll a, ll b, ll n) {
    ll res = 0;
    while(b) {
    if(b&1) res = (res + a) % n;
    a = (a + a) % n;
    b >>= 1;
    }
    return res;
    }
    //a^b % n
    //同理
    ll mod_exp(ll a, ll b, ll n) {
    ll res = 1;
    while(b) {
    if(b&1) res = mod_mul(res, a, n);
    a = mod_mul(a, a, n);
    b >>= 1;
    }
    return res;
    }

    下面开始说Miller-Rabin测试:

      费马小定理:对于素数p和任意整数a,有ap ≡ a(mod p)(同余)。反过来,满足ap ≡ a(mod p),p也几乎一定是素数。

      伪素数:如果n是一个正整数,如果存在和n互素的正整数a满足 an-1 ≡ 1(mod n),我们说n是基于a的伪素数。如果一个数是伪素数,那么它几乎肯定是素数。

      Miller-Rabin测试:不断选取不超过n-1的基b(s次),计算是否每次都有bn-1 ≡ 1(mod n),若每次都成立则n是素数,否则为合数。 

    伪代码:

    Function Miller-Rabin (n : longint) :boolean;
    begin
    for i := 1 to s do
    begin
    a := random(n - 2) + 2;
    if mod_exp(a, n-1, n) <> 1 then return false;
    end;
    return true;
    end;


    注意,MIller-Rabin测试是概率型的,不是确定型的,不过由于多次运行后出错的概率非常小,所以实际应用还是可行的。(一次Miller-Rabin测试其成功的概率为3/4)

    前边说的伪代码实现很简短,下面还有一个定理,能提高Miller测试的效率:

    二次探测定理

      如果p是奇素数,则 x2 ≡ 1(mod p)的解为 x = 1 || x = p - 1(mod p);

    可以利用二次探测定理在实现Miller-Rabin上添加一些细节,具体实现如下:

    bool miller_rabin(ll n) {
    if(n == 2 || n == 3 || n == 5 || n == 7 || n == 11) return true;
    if(n == 1 || !(n%2) || !(n%3) || !(n%5) || !(n%7) || !(n%11)) return false;

    ll x, pre, u;
    int i, j, k = 0;
    u = n - 1; //要求x^u % n

    while(!(u&1)) { //如果u为偶数则u右移,用k记录移位数
    k++; u >>= 1;
    }

    srand((ll)time(0));
    for(i = 0; i < S; ++i) { //进行S次测试
    x = rand()%(n-2) + 2; //在[2, n)中取随机数
    if((x%n) == 0) continue;

    x = mod_exp(x, u, n); //先计算(x^u) % n,
    pre = x;
    for(j = 0; j < k; ++j) { //把移位减掉的量补上,并在这地方加上二次探测
    x = mod_mul(x, x, n);
    if(x == 1 && pre != 1 && pre != n-1) return false; //二次探测定理,这里如果x = 1则pre 必须等于 1,或则 n-1否则可以判断不是素数
    pre = x;
    }
    if(x != 1) return false; //费马小定理
    }
    return true;
    }

      前边这个算法经过测试还是比较靠谱的,可以用作模板。本菜也找过其他模板,可是有的居然把9测成素数,汗 -_-!


    AC_Von 原创,转载请注明出处:http://www.cnblogs.com/vongang/archive/2012/03/15/2398626.html

  • 相关阅读:
    electron 整合 serialport
    javascript 中字符串转化utf8字节数组, 然后在将字节数组转化十六进制字符串
    linux 之 非root用户安装mysql5.7.27
    linux(CentOS7) 之 zookeeper 下载及安装
    linux(CentOS7) 之 ntp时间同步配置步骤
    linux(CentOS7) 之 克隆虚拟机并配置网络(固定ip)
    linux(CentOS7) 之 MySQL 5.7.30 下载及安装
    linux(CentOS7) 之 jdk1.8 下载及安装
    Vue.prototype定义原型属性或方法
    Map接口中的常用方法
  • 原文地址:https://www.cnblogs.com/vongang/p/2398626.html
Copyright © 2011-2022 走看看