模数指数的极快方法,模数和指数为几百万位

时间:2014-07-11 10:52:29

标签: performance algorithm math number-theory modular-arithmetic

作为一个业余爱好项目,我正在努力寻找真正庞大的素数。对此的素性测试包含modular exponentiation计算,即一个^ e mod n。让我们将其称为modpow操作,以使解释变得简单。我想加快这个特定的计算。

目前我正在使用GMPmpz_pown功能,但它有点慢。我认为它太慢的原因是因为对GMP的modpow的函数调用比对于相同大数的称为PFGW的软件的完整素性测试慢。 (所以要清楚,这只是GMP的modpow部分,而不是我正在比较的整个自定义素性测试程序)。 PFGW在其领域被认为是最快的,对于我的用例,它使用Brillhart-Lehmer-Selfridge素性测试 - 它也使用modpow程序 - 所以它不是因为数学上的聪明,PFGW更快在这方面(如果我在这里错了,请纠正我)。看起来GMP的瓶颈是modpow操作。对于具有超过20,000个数字的数字的示例运行时:GMP的modpow操作大约需要45秒,而PFGW在9秒内完成整个素数测试(涉及一个modpow)。对于更大的数字,差异变得更加令人印象深刻。 GMP使用FFT乘法和蒙哥马利减少进行此测试比较,请参阅下面这篇文章的评论。

我做了一些研究。到目前为止,我理解modpow算法通过平方,整数乘法和模数减少使用取幂 - 这些对我来说都非常熟悉。几种辅助方法可以改善整数乘法的运行时间:

为了通过对部分求平方来改善取幂的运行时间,可以使用有符号的数字表示来减少乘法的数量(即,比特表示为0,1或-1,并且比特串表示为这样的方式使它包含比原始base-2表示更多的零 - 这通过平方减少了求幂的运行时间。

为了优化操作的模数部分,我知道这些方法:

所以这里是150,000美元问题:是否有一个软件库可以在给定非常大的基数,指数和模数的情况下有效地进行modpow运算? (我瞄准数百万的数字)。如果您想建议一个选项,请尝试解释算法的内部工作原理,包括基数,模数和指数的数百万位数,因为有些库根据位数使用不同的算法。基本上我正在寻找一个支持上述技术的库(或者可能更聪明的技术),并且它在运行算法时应该表现良好(至少比GMP好)。到目前为止,我已经搜索,发现并尝试了GMP和PFGW,但没有发现这些令人满意(PFGW很快,但我只对modpow操作感兴趣,并且没有直接的编程接口那)。我希望可能是该领域的专家可以建议具有这些功能的库,因为似乎很少能够处理这些要求。

修改:使问题更加简洁,因为它标记得过于宽泛。

2 个答案:

答案 0 :(得分:5)

首先,重新开始。答案1作者的评论“我不使用GMP,但我怀疑他们写作时使用的是FFT 它们真的意味着NTT“ - 不,当GMP说”FFT“时它意味着浮点FFT。 IIRC他们也有一些基于NTT的例程,但对于bignum mul而言,这些与FFT无竞争力。

经过良好调整的FFT-mul击败任何NTT的原因是由于舍入误差累积导致的每字精度的轻微损失超过了现代CPU产品的极佳浮点能力,特别是当人们考虑利用CPU(例如x86_64系列)的矢量数学功能的高性能实现时,其当前的迭代--Intel Haswell,Broadwell和Skylake - 具有大量的矢量浮点功能。 (我不会在这方面引用AMD,因为他们的AVX产品远远落后于英特尔;他们的高水位大约是在2002年左右,从那以后英特尔每年都在以逐渐恶化的方式击败它们。)原因这方面的GMP令人失望的是,相对而言,GMP的FFT是废话。我总体上非常尊重GMP编码器,但是FFT时序是FFT时序,你没有得到点努力或者例如有一个非常好的bignum添加。这是一篇详细介绍了大量GMP FFT-mul改进的论文:

Pierrick Gaudry,Alex Kruppa,Paul Zimmerman:“基于GMP的Schönhage-Strassen大整数乘法算法的实现”[http://www.loria.fr/~gaudry/publis/issac07.pdf]

这是从2007年开始,但AFAIK下面的片段中所记录的性能差距并没有缩小;如果它有任何扩大的话。这篇论文非常适合详细介绍可以部署的各种数学和算法改进,但让我们切入金钱报价:

“为整数乘法实现复杂浮点FFT的程序是George Woltman的Prime95。它主要用于测试大型Mersenne数2 ^ p - 1中的素数,用于大互联网Mersenne Prime搜索[24]它使用DWT进行乘法mod a * 2 ^ n±c,a和c不太大,见[17]。我们比较了Prime95版本24.14.2中的乘法模2 ^ 2wn - 1与n字的乘法在3.2 GHz的奔腾4和2.4 GHz的Opteron 250上使用我们的SSA实现的整数,见图4.很明显,Prime95大大超过了我们的实现,实际上通常超过了Pentium 4上有10个,Opteron上有2.5到3个因子。“

接下来的几段是一大堆节省面子的旋转。 (再次,我个人认识了3位作者中的2位,他们都是计算数论领域的顶尖人物。)

请注意前面提到的George Woltman,其Prime95代码自20年前首次亮相后不久就发现了所有世界纪录的素数,使得他的核心bignum例程以一般的API形式提供,称为GWNUM库。您提到PFGW比FFT-mul的GMP快多少 - 这是因为PFGW使用GWNUM进行核心“繁重”算术,这就是PFGW中'GW'的来源。

我自己的FFT实现,它具有泛型C构建支持,但像George一样使用大量的x86矢量数学汇编程序来获得该CPU系列的高性能,比目前的英特尔处理器系​​列上的George慢大约60-70%。我相信这使它成为x86上世界上第二快的bignum-mul代码。举例来说,我的代码当前正在使用30-M双倍FFT(30 * 2 ^ 20双倍)对大约2 ^ 29位的数字运行素性测试;因此每个输入字略多于17位。使用我的所有四个3.3 GHz Haswell 4670 quad核心,每个模块需要大约90 ms。

顺便说一句,很多(如果不是大多数)世界顶级的bignum数学编码人员都在mersenneforum.org上闲聊,我鼓励你查看一下并向更广泛的(至少在这个特定领域)专家观众提问。那里。我出现在这里的同一个句柄下面;乔治·沃尔特曼(George Woltman)出现为“Prime95”,PFGW的马克·罗登基希(Mark Rodenkirch)饰演“流氓”。

答案 1 :(得分:3)

我根本不使用 GMP ,所以请记住这一点。

  1. 我宁愿使用NTT代替FFT进行乘法

    它消除了舍入误差,与我的 FFT 相比,优化到同一点的实现更快

    正如我所提到的,我不使用GMP,但我怀疑他们写的时候使用 FFT 他们的意思是 NTT (有限域傅里叶变换)

    < / LI>
  2. 您的测试和GMP素性测试的速度差异可能由modpow电话引起。

    如果有太多的调用,那么它会导致堆/堆垃圾,这会大大减慢速度。特别是bignums。尽量避免堆垃圾,以便从操作数中消除尽可能多的数据,并尽可能为经常调用的函数返回调用。另外,有时通过直接将函数源代码复制到代码中而不是使用局部变量调用(或使用宏代码)来帮助消除瓶颈调用。

    我认为 GMP 发布了他们的源代码,因此找到modpow的实现应该不会太难。你只需要正确使用它

  3. 只是为了清楚

    您使用的是20000+十进制数字这样的大数字,这意味着每个数字~8.4 KBytes。任何返回或非指针操作数意味着将数据量复制到堆栈中或从堆栈中复制。这不仅需要时间,而且通常会使 CPU CACHE 无效,这也会导致性能下降。

    现在将其乘以算法迭代次数,即可获得Idea。在调整我的许多bignum函数时遇到类似的问题,并且即使所使用的算法没有变化,加速也经常超过10000%100次)。只是限制/消除堆/堆栈垃圾。

    所以我认为你不需要更好的modpow实现只是更好地使用它,但粗略的我可能是错的但没有你使用的代码很难推断更多。