Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 对10^18以内的数字进行素因子分解的最快方法_Algorithm_Primes_Prime Factoring_Sieve Of Eratosthenes_Factorization - Fatal编程技术网

Algorithm 对10^18以内的数字进行素因子分解的最快方法

Algorithm 对10^18以内的数字进行素因子分解的最快方法,algorithm,primes,prime-factoring,sieve-of-eratosthenes,factorization,Algorithm,Primes,Prime Factoring,Sieve Of Eratosthenes,Factorization,给定一个数1>=1; 基数=(基数*基数)%mod; } 返回ret; } ull gcd(ull x,ull y){ while(y){ 温度=y; y=x%y; x=温度; } 返回x; } ull pollardrho(ull n){ srand(时间(空)); 如果(n==1) 返回n; ull x=(rand()%(n-2))+2; y=x; ull c=(rand()%(n-1))+1; ull d=1; 而(d==1){ x=(模流(x,2,n)+c+n)%n; y=(模流(y,2

给定一个数
1>=1;
基数=(基数*基数)%mod;
}
返回ret;
}
ull gcd(ull x,ull y){
while(y){
温度=y;
y=x%y;
x=温度;
}
返回x;
}
ull pollardrho(ull n){
srand(时间(空));
如果(n==1)
返回n;
ull x=(rand()%(n-2))+2;
y=x;
ull c=(rand()%(n-1))+1;
ull d=1;
而(d==1){
x=(模流(x,2,n)+c+n)%n;
y=(模流(y,2,n)+c+n)%n;
y=(模流(y,2,n)+c+n)%n;
d=gcd(绝对值(x-y),n);
如果(d==n){
返回pollardrho(n);
}
}
返回d;
}
int main()
{
ios_base::与_stdio同步(false);
cin.tie(0);
initprime();
ulln;
cin>>n;
ull c=n;
向量o;
对于(向量::迭代器i=p.begin();i!=p.end();++i){
ull t=*i;
如果(!(n%t)){
o、 推回(mp(t,0));
}
而(!(n%t)){
n/=t;
o[o.size()-1].y++;
}
}
而(n>1){
ull u=pollardrho(n);
o、 推回(mp(u,0));
而(!(n%u)){
n/=u;
o[o.size()-1].y++;
}
如果(n<10000005){
if(素数[n]){
o、 推回(mp(n,1));
}
}
}
返回0;
}

有没有更快的方法来计算这些数字?如果可能的话,请解释原因以及源代码。

在现代处理器上,64位输入的最快解决方案是少量试用除法(数量会有所不同,但通常低于100),然后是Pollard的Rho。您需要使用Miller-Rabin或BPSW进行良好的确定性素性测试,以及处理多个因素的基础设施(例如,如果一个组合被拆分为多个组合)。对于32位,您可以进一步优化这些功能

你会想要一个快速的mulmod,因为它是Pollard的Rho、Miller Rabin和Lucas测试的核心。理想情况下,这是作为一个微小的汇编程序片段来完成的

计算任何64位输入的因数的时间应小于1毫秒。在50位以下速度明显加快

如Ben Buhrow的spBrent实现所示,Brent 1980年论文中的算法P2''似乎与我所知道的其他实现一样快。它使用了布伦特改进的周期发现,以及通过必要的附加回溯延迟GCD的有用技巧

有关各种解决方案的一些混乱细节和基准测试,请参阅。我有许多不同规模的这些和其他实现的基准测试,但还没有发布任何东西(部分原因是有很多方法可以查看数据)

由此产生的一个真正有趣的事情是,多年来被认为是64位范围高端的更好解决方案的SQUFOF不再具有竞争力。SQUFOF的优势在于,它只需要一个快速的完美方形检测器就可以获得最佳速度,而不必在asm中才能达到真正的快速。

假设您有一个数字
n
,它的最大值为1018,并且您希望对其进行素数分解。因为这个数字可以小到单位,也可以大到1018,所以它可以是素数,也可以是复合数,这就是我的方法-

  • 使用时,请确保数字是复合的
  • Factorse
    n
    使用最大为106的素数,可使用计算
  • 现在,
    n
    的更新值使得它只有106以上的素数因子,并且由于
    n
    的值仍然可以大到1018,因此我们得出结论,该数字要么是素数,要么正好有两个素数因子(不一定不同)

  • 再次运行Miller Rabin以确保数字不是素数
  • 用于获取一个素因子
  • 你现在有了完整的因子分解

    让我们看看上述方法的时间复杂性:

    • 米勒·拉宾采用
      O(对数n)
    • Eratosthenes筛取
      O(n*logn)
    • Pollard rho I shared的实现需要
      O(n^0.25)
    时间复杂性 步骤2所用的最大时间等于
    O(10^7)
    ,这又是上述算法的复杂性。这意味着您可以在一秒钟内找到几乎所有编程语言的因式分解

    空间复杂性 空间仅在步骤2中使用,在步骤2中,筛子被实现,并且等于
    O(10^6)
    。同样,这是非常实用的

    实施 在
    C++14
    中实现。代码有一个隐藏的bug。您可以在下一节中显示它,也可以跳过挑战;)

    代码中的Bug 在
    第105行
    中,迭代直到
    i=
    p
    ,这样至少有一个等于
    p
    将导致错误的素因子分解

    奖金方案 总共有四个这样的数字:{P03,P02P1,P02P2,P0P12},其中P0=p=999983,P1=next_prime(P0)=1000003,P2=next_prime(P1)=1000033


    有一些椭圆曲线的东西。我不记得名字了,但网上有代码。你会花很多时间来考虑你的范围内的大素数(>10^14)。你可以在筛选结束后快速进行素数测试,省去寻找大素数因子的麻烦。@rossum我一直在考虑这个问题。但是我找不到任何算法来测试素性,它的复杂度小于O(sqrt(n)),并且不会占用大量内存@Štef Miller Rabin会占用大量内存吗?IIRC该测试可以重复进行,直到假阳性的几率小于计算机硬件故障的几率。它看起来非常好。您可能有该算法的实现吗?@Stef yes我为上面使用的所有算法添加了github repo中的代码片段。如果你要求的话,我可以在一个小时内添加一个完整的工作
    C++14
    代码,因为我现在正在旅行
    #include <iostream>
    #include <vector>
    #include <cstdio>
    #include <ctime>
    #include <cmath>
    #include <cstdlib>
    #include <algorithm>
    #include <string>
    
    using namespace std;
    
    typedef unsigned long long ull;
    typedef long double ld;
    typedef pair <ull, int> pui;
    #define x first
    #define y second
    #define mp make_pair
    
    bool prime[10000005];
    vector <ull> p;
    
    void initprime(){
        prime[2] = 1;
        for(int i = 3 ; i < 10000005 ; i += 2){
            prime[i] = 1;
        }
        for(int i = 3 ; i * i < 10000005 ; i += 2){
            if(prime[i]){
                for(int j = i * i ; j < 10000005 ; j += 2 * i){
                    prime[j] = 0;
                }
            }
        }
        for(int i = 0 ; i < 10000005 ; ++i){
            if(prime[i]){
                p.push_back((ull)i);
            }
        }
    }
    
    ull modularpow(ull base, ull exp, ull mod){
        ull ret = 1;
        while(exp){
            if(exp & 1){
                ret = (ret * base) % mod;
            }
            exp >>= 1;
            base = (base * base) % mod;
        }
        return ret;
    }
    
    ull gcd(ull x, ull y){
        while(y){
            ull temp = y;
            y = x % y;
            x = temp;
        }
        return x;
    }
    
    ull pollardrho(ull n){
        srand(time(NULL));
        if(n == 1)
            return n;
        ull x = (rand() % (n - 2)) + 2;
        ull y = x;
        ull c = (rand() % (n - 1)) + 1;
        ull d = 1;
        while(d == 1){
            x = (modularpow(x, 2, n) + c + n) % n;
            y = (modularpow(y, 2, n) + c + n) % n;
            y = (modularpow(y, 2, n) + c + n) % n;
            d = gcd(abs(x - y), n);
            if(d == n){
                return pollardrho(n);
            }
        }
        return d;
    }
    int main ()
    {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    initprime();
    ull n;
    cin >> n;
    ull c = n;
    vector <pui> o;
    for(vector <ull>::iterator i = p.begin() ; i != p.end() ; ++i){
        ull t = *i;
        if(!(n % t)){
            o.push_back(mp(t, 0));
        }
        while(!(n % t)){
            n /= t;
            o[o.size() - 1].y++;
        }
    }
    while(n > 1){
        ull u = pollardrho(n);
        o.push_back(mp(u, 0));
        while(!(n % u)){
            n /= u;
            o[o.size() - 1].y++;
        }
        if(n < 10000005){
            if(prime[n]){
                o.push_back(mp(n, 1));
            }
        }
    }
    return 0;
    }