非常有趣的问题,谢谢!
整天都在编写 C++ 代码,从头开始实现非常快速的椭圆曲线ECM分解方法和亲和数搜索。
众所周知,ECM方法非常非常快。如果优化得好,这种 ECM 方法甚至可以在一秒钟内找到100位数字(由两个50位质数组成)的因子。它只比二次筛法和GNFS慢。
正如你所说的,你正在寻找25位数字的亲和数,这是80位数字。
根据我在下面的C++程序中测量,在我的旧2核笔记本电脑上,它可以因式分解每秒钟大小为80位(25位数字)的150个随机数(我设置了一个计时器来截断难以因式分解的数字)。如果它们的大小为27-30位(9位数字),则可以因式分解20,000个数字。
我上面说过易于因式分解的集合
。似乎所有大小为80位(25位数字)的随机数中有60-70%是易于因式分解的,这意味着仅需要7毫秒即可因式分解单个数字,从而每秒产生150个数字。
我将仅在易于因式分解的数字中搜索亲和数。易于因式分解的集合中与其他集合中一样多的亲和数。亲和数不会受到易于因式分解过滤的影响。
以下是我的程序使用ECM分解搜索27位亲和数的控制台输出:
.46501 _43919 *41268 , 20512 nums/sec, tdiv 99.34% 7mcs, ecm 25.3% 39mcs, total 37mcs, done 7%
found (97041735, 97945785)
.321639 _303557 *285333 , 20389 nums/sec, tdiv 99.35% 7mcs, ecm 25.4% 40mcs, total 38mcs, done 48%
found (34765731, 36939357)
.29933 _28247 *26517 , 20265 nums/sec, tdiv 99.35% 7mcs, ecm 25.4% 40mcs, total 38mcs, done 4%
found (9773505, 11791935)
.529659 _499736 *470070 , 19312 nums/sec, tdiv 99.35% 7mcs, ecm 25.5% 41mcs, total 40mcs, done 79%
found (5357625, 5684679)
.25937 _24411 *22905 , 19340 nums/sec, tdiv 99.35% 7mcs, ecm 25.4% 41mcs, total 40mcs, done 4%
found (998104, 1043096)
.26367 _24902 *23462 , 19360 nums/sec, tdiv 99.35% 7mcs, ecm 25.5% 41mcs, total 40mcs, done 4%
found (1184, 1210)
.130374 _122896 *115508 , 19648 nums/sec, tdiv 99.35% 7mcs, ecm 25.5% 40mcs, total 39mcs, done 20%
found (35390008, 39259592)
found (133178325, 133471275)
.32032 _30226 *28368 , 19753 nums/sec, tdiv 99.35% 7mcs, ecm 25.5% 40mcs, total 39mcs, done 5%
found (898216, 980984)
从上面可以看到,程序在找到某些内容时会输出found
和友好数。此外,它还显示了一些关于速度和时间的详细统计信息。如果您像我一样每秒搜索20,000个数字,则需要几秒钟才能找到一个27位大小的友好数。
如果您考虑80位数字(25位数字),那么尽管我每秒因子分解150个数字,但友好数非常少,以至于要找到至少一个这样的80位友好数需要数万亿秒。以下是这个80位因式分解的统计数据。您可以看到,在几秒钟内,它仅完成了0.0000000000064%的工作量,找到了单个友好数对,整个工作量非常小。
.4218 _2261 *1699 , 123 nums/sec, tdiv 43.81% 133mcs,
ecm 2.8% 1886mcs, total 8144mcs, done 0.0000000000064%
你可能听说过Amicable Numbers for BOINC项目 - 这是一个伟大的分布式搜索,用于查找这些数字。数百万台计算机正在搜索它们。当然,如果有数百万台计算机,它们可以更快地找到一些数字。事实上,它们已经找到了1_227_817_736个这样的数字,数量真的很大,在此处查看所有数字。
在我的C++程序中,我还展示了我的ECM因子分解器作为示例,在程序启动时,我对100位随机数进行了非常快速的因子分解。它显示类似于以下的控制台输出:
Initial N to factor with ECM: 1044877821881837432173434582227 (100-bit)
Number of threads 2.
Factors TrialDivA: [2953]
Factoring 35383603856479425437736059
Curves [ 0, 8), bound 2^ 9.000, 0.110 sec
Curves [ 8, 16), bound 2^ 10.000, 0.222 sec
Curves [ 16, 24), bound 2^ 10.585, 0.418 sec
Curves [ 24, 32), bound 2^ 11.000, 0.416 sec
Curves [ 32, 40), bound 2^ 11.322, 0.401 sec
Factors ECM: [21788197859]
Fully factored. N 1044877821881837432173434582227: [2953, 21788197859, 16239802890289801]
Time 1.692 sec.
您可以看到,仅需要1秒钟即可因数分解相当复杂的100位数。如上所述,首先我使用试除法阶段,这是最简单的因式分解算法,可在O(Sqrt(N))
时间内工作。在试除法之后,我创建许多具有不断增长边界的曲线,每条新曲线都有更大的分解数字机会,但需要更长的时间。
根据维基百科中的ECM,我的ECM算法如下:
尝试使用试除法方法找到小的质因数。在此步骤中花费总时间的5-10%。从数字中删除找到的因子。
使用32次Fermat概率测试检查数字是否可能是质数,并具有高置信度。为了克服Carmichael数,您还可以使用Miller Rabin测试。如果数字是质数,则将其作为唯一因子返回。
随机生成曲线参数A,X,Y
并从曲线方程式Y ^ 2 = X ^ 3 + AX + B(mod N)
中导出B
。检查曲线是否正确,值4 * A ** 3 - 27 * B ** 2
应为非零。
通过Eratosthenes筛法生成小质数,小于我们的Bound。每个质数都升至某个小幂,这个升起的质数称为K。当它小于某个Bound2时,我进行幂运算,我的情况下是Sqrt(Bound)
。
计算椭圆点乘法P = k * P
,其中K取自上一步,P为(X,Y)。根据椭圆曲线乘法Wiki计算。
点乘法使用模反演,它根据扩展欧几里得算法Wiki计算GCD(SomeValue,N)
(最大公约数)。如果此GCD不为1,则它会给出N的非1因子,因此我们找到了一个因子,可以推进ECM算法以搜索剩余的因子。
如果所有小于Bound的质数相乘并没有给出因子,则再次使用另一个随机曲线和更大的Bound重新运行ECM分解算法(上述3-6步)。在我的代码中,我通过将旧边界加512来获取新边界。
如果你想调整我的代码以计算其他位大小,那么请查看Test()
函数。将bits_factor = 100
修改为其他值,这将设置因子100位随机数作为示例。这个bits_factor变量仅控制因式分解的示例。如果你想设置要搜索的亲和数位数,可以修改bits_amicable_max = 27
,27代表27位数字,你可以将其设置为80以查找80位亲和数。
在我的代码中,我支持三种不同的大整数实现源,它们允许您拥有任何大位数,甚至数千位。第一个源是CLang/GCC内置的
__int128
,这为您提供了128位整数算术运算。如果您使用其他编译器,可以禁用宏
SUPPORT_STD_U128
。其次,我使用了
Boost.Multiprecision库,它允许您有效地进行1024位以下的大整数算术运算,如果您不想使用Boost,则禁用宏
SUPPORT_BOOST
。然后我使用了
GMP Library,这使您可以拥有甚至数百万位的位数,如果您不想使用GMP,则禁用
SUPPORT_GMP
。
在Linux下安装Boost和GMP很容易,sudo apt install libgmp-dev libboost-all-dev
。在Windows中,您需要先安装VCPKG包管理器,然后在其安装文件夹内执行vcpkg install boost gmp
。
如果您想在GodBolt服务器上在线运行我的代码,请单击下面的Try it online!
链接。但请注意,GodBolt版本的代码与下面Github Gist中的代码不同,这个GodBolt版本将参数大小缩小以使程序运行更快,因为他们的服务器对程序运行有非常严格的限制,可能只有5-10秒钟。
源代码在此处。在Try it online!
链接下面有Github Gist链接。我把我的代码放在那里,因为它的大小为36 KB
,而StackOverflow的帖子大小限制总共只有30,000个字符,所以帖子文本和源代码加起来就太多了。
在 GodBolt 上在线尝试!
Github Gist 完整源代码