• Miller_raibin算法随机化检测素数 & Pollar_rho 算法分解大数


    这几天一直再学习这些内容,也没有发一些博客,现在我觉得差不多了

    首先基础是Miller_raibin随机化检测素数,顾名思义,随机化也就是有几率不对,但是很低,适用于大数快速检测,因为大数已经超出了我们打表的范围了

    对于这个算法基础是费马小定理 和二次探测定理

    1. Fermat定理:若n是奇素数,a是任意正整数(1≤ a≤ n−1),则 a^(n-1) ≡ 1 mod n。
    2. 推演自Fermat定理(具体过程我没看懂,Orz), 如果n是一个奇素数,将n−1表示成2^s*r的形式,r是奇数,a与n是互素的任何随机整数,那么a^r ≡ 1 mod n或者对某个j (0 ≤ j≤ s−1, j∈Z) 等式a^(2jr) ≡ −1 mod n 成立。

    他们的命题前提条件都是如果n是素数……,但是反过来却不一定对,但有可能对,我们只要把这个可能无限的放大,就好了

    https://blog.csdn.net/semiwaker/article/details/60142102

    首先快速乘法,快速幂

    typedef long long ll;
    ll retmin;
    ll q_mul(ll a,ll b,ll c)
    {
        ll res = 0;
        a %= c;
        while(b)
        {
            if(b & 1) res = (res + a) % c;
            b >>= 1;
            a = (a + a) % c;
        }
        return res;
    }
    ll q_pow(ll a,ll b,ll c)
    {
        ll res = 1;
        a %= c;
        while(b)
        {
            if(b & 1)res = q_mul(res,a,c);
            b >>= 1;
            a = q_mul(a,a,c);
        }
        return res;
    }
    

     然后就是随机化验证,对于随机数我用的是网上的经验取值,2,7,61这样基本上达到100%

    bool miller_rabin(ll n)
    {
        if(n == 2 || n == 7 || n ==61)return true;
    
        if(n < 2 || !(n & 1))return false;
    
        if(witness(2,n) && witness(7,n) && witness(61,n))
            return true;
        return false;
    }
    

     如何验证呢?

    对于费马小定理,我们直接去看a的n-1次方有点太暴力,最优的就是把以上两个定理的逆定理合起来一起验证!

    我们考虑把费马小定理中的n - 1分解为 2^t*u

    ll u = n - 1;
        int t = 0;
    
        while(!(u & 1))
        {
            u >>= 1;
            t++;
        }
    

     把2分解出来才能取构造平方~~去验证二次探测定理

    更详细的解释还得看这个大佬的博客

    if(u == 1 || u == n - 1)return true;
    
        while(t--)
        {
            u = q_mul(u,u,n);
            if(u == n - 1)
                return true;
        }
        return false;
    

     如果一旦出现n-1的值那么代表提供了二次探测,一开始值若为1代表提供了费马小,所以对于这次测试,它能够通过

    接下来我们进行大数分解算法,其实主要目的就是去找它的因子

    void Find(ll n)
    {
        if(n == 1)return;
    
        if(miller_rabin(n))
        {
            retmin = min(retmin,n);
            return;
        }
    
        ll p = n;
    
        while( p >= n)
            p = pollard_rho(n,rand() % (n - 1) + 1);
        Find(p);
        Find(n / p);
    }
    

     如代码,我们尝试去找n的因子,前面特判一些,如果n不是素数,那就有因子,我们用pollard算法去寻找

    一开始我们找因子就是一个一个去试,效率非常低,但是我们如果能够利用组合,我提供一堆数,两两组合求差,用差去尝试,那样效率会大大提升,你可能觉得没什么区别,但是你可以去查一下生日悖论

    他很好的说明了这个算法的高效性

    再优化一点呢,就是随机数我们有自己的生成机制和步长限制(循环),所以,

    ll pollard_rho(ll n,ll c)
    {
        ll x,y,d,i = 1,k = 2;
    
        x = rand() % ( n - 1) + 1;
        y = x;
        while(1)
        {
            x = (q_mul(x,x,n) + c) % n;
            d = gcd((x - y + n) % n,n);
    
            if(d > 1 && d < n)return d;
    
            if(x == y)return n;
    
            if(++i == k)
            {
                k <<= 1;
                y = x;
            }
        }
    }
    

     如果x == y代表我们随机选择的参数c不好,达到了循环,所以重新进行寻找

  • 相关阅读:
    在vue项目中使用codemirror插件实现代码编辑器功能(代码高亮显示及自动提示)
    解决request.getSession().getServletContext().getRealPath("/")为null问题
    redis数据类型为key的常用命令
    spring boot知识清单
    java 百度地图判断两点距离2
    java 百度地图判断两点距离1
    百度地图js判断点是否在圆形区域内
    百度地图java 判断当前位置是否在多边形区域内
    redis学习之路
    burpsuite插件使用
  • 原文地址:https://www.cnblogs.com/DF-yimeng/p/8653795.html
Copyright © 2020-2023  润新知