• 快速素数测试(Miller-Robin)


    typedef long long ll;
    typedef __int128 lll;
    const int S = 20;//随机算法判定次数,S越大,判错概率越小,一般5~20
    inline ll fp(ll b, ll p, ll mod) {
        ll ans = 1;
        while (p) {
            if (p & 1)
                ans = (lll)ans * b % mod;
            p >>= 1;
            b = (lll)b * b % mod;
        }
        return ans;
    }
    bool check(ll a, ll n, ll x, ll t) {
        ll ret = fp(a, x, n);
        ll last = ret;
        for (int i = 1; i <= t; i++) {
            ret = (lll)ret * ret % n;
            if (ret == 1 && last != 1 && last != n - 1)
                return 1;//合数
            last = ret;
        }
        if (ret != 1)
            return 1;
        return 0;
    }
    bool Miller_Rabin(ll n) {
        if (n < 2) return 0;
        if (n == 2) return 1;
        if ((n & 1) == 0) return 0;//偶数
        ll x = n - 1;
        ll t = 0;
        while ((x & 1) == 0) {
            x >>= 1;
            t++;
        }
        for (int i = 0; i < S; i++) {
            ll a = rand() % (n - 1) + 1;
            if (check(a, n, x, t))
                return 0;//合数
        }
        return 1;
    }
    
    /*
    只能测试3e9以内的数,如果要测试long long范围内的数,需要将快速幂中的乘法换成快速乘
    本地测试估计:1e9内,时间约为O(100),1e18内,时间约为O(15000)
    */
    inline ll fm(ll x,ll y,ll mod){
        ll ans=0;
        while(y>0){
            if(y&1)ans=(ans+x)%mod;
            y>>=1;
            x=(x+x)%mod;
        }
        return ans;
    }
    inline ll fp(ll b,ll p,ll mod){
        ll ans=1;
        while(p){
            if(p&1)ans=fm(ans,b,mod);
            p>>=1;
            b=b*b%mod;//在判断ll范围内的数时,要用下面这个代替
            //b=fm(b,b,mod);
        }
        return ans;
    }
    int strong_pseudo_primetest(ll n, int base) {
        ll n2 = n - 1, res;
        int s = 0;
        while (n2 % 2 == 0) n2 >>= 1, s++;
        res = fp(base, n2, n);
        if ((res == 1) || (res == n - 1)) return 1;
        s--;
        while (s >= 0) {
            res = fm(res, res, n);
            if (res == n - 1) return 1;
            s--;
        }
        return 0;// n is not a strong pseudo prime
    }
    int isprime(ll n) {
        static ll testNum[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};
        static ll lim[] = {4, 0, 1373653ll, 25326001ll,25000000000ll, 2152302898747ll, 3474749660383ll, 341550071728321ll,0, 0, 0, 0};
        if (n < 2 || n == 3215031751ll) return 0;
        for (int i = 0; i < 12; ++i) {
            if (n < lim[i]) return 1;
            if (strong_pseudo_primetest(n, testNum[i]) == 0) return 0;
        }
        return 1;
    }
    
  • 相关阅读:
    发送邮件
    C#操作Excel总结
    注意!监控MySQL服务是否正常,懂这4种方法就可以了
    Linux磁盘空间爆满怎么办?定时文件清理脚本配置实现
    Linux 服务器必备的安全设置,建议收藏!
    MySQL入门到精通:MySQL 选择数据库
    TIOBE3月榜单公布!C 语言稳居第一,将新增功能,消除差异
    C++如何读取带空格字符串?这5种方法教会你
    C语言丨二分查找算法详解(含示例代码)
    线上故障了!居然是因为Linux磁盘缓存机制导致的
  • 原文地址:https://www.cnblogs.com/ucprer/p/14075570.html
Copyright © 2020-2023  润新知