我使用Pollard's Rho and Brent's algorithms(参见:https://stackoverflow.com/a/31978350/44080)
在VB.Net中使用BigInteger实现了Prime Factorization的良好解决方案对于N< 2^63
,我相信UInt64
应该足够大,并且可能(很多?)更快。
但是,此行UInt64
转换失败:
y = ((y^2) Mod n + c) Mod n 'fails when y^2 > UInt64.Max
将此行更改为
y = CULng((CDbl(y^2) Mod n + c) Mod n)
因类型转换处于循环中而导致性能下降。
请问我该如何解决这个问题?
如果我们能够解决上述问题,我仍然认为UInt64将会执行BigInteger。
修改
我刚刚发现:Dirichlet .NET Number Theory Library声称拥有Int128和Int256可以执行.Net BigInteger。
它甚至还有几种优化的Prime数分解算法。本可以节省我2天的研究和测试。
答案 0 :(得分:1)
如何执行模块化乘法(计算平方)而不溢出:
只要模数至少比最大值小一位,解决方法就是将数字分成低位和高位的一半,然后执行算术零碎,有点像小学 - 学校乘法你在哪里乘以一个数字,然后移动总和并乘以十位,依此类推,除了“数字”是可以用整数数据类型表示的最大数的平方根的大小。
考虑使用8位算术计算56 * 37模100的示例,因此没有中间总数可以是256或更大。我们首先表示a = 56 = 3 * 16 + 8和b = 37 = 2 * 16 + 5,(注意16是256的平方根)所以:
a1 = 8
a2 = 3
b1 = 5
b2 = 2
然后四个中间产品的变化是:
p11 = 8 * 5 = 40
p12 = 8 * 2 = 16 > 32 > 64 > 128 (28) > 56
p21 = 3 * 5 = 15 > 30 > 60 > 120 (20) > 40
p22 = 3 * 2 = 6 > 12 > 24 > 48 > 96 > 192 (92) > 184 (84) > 168 (68) > 136 (36)
我们正在使用二进制算术,所以每个数字在移位时都会加倍,在我们去的时候取模100。两个低半数的乘积没有移位,低半数和高半数的乘积被移位4次(因为log 2 16 = 4),并且两个高的乘积 - 半数转移8次。然后对中间产物求和,每次中间和超过m时再次除去m:
s = 40 + 56 = 96
s = 96 + 40 = 136 (36)
s = 36 + 36 = 72
这是最终答案:56 * 37 = 2072,即72(mod 100)。
如果m在整数数据类型的最大值的一位内,则事情变得更加混乱;基本答案是分为三个部分,计算中间产品,并重新组合。
有关Scheme中的代码,请参阅my blog,以及使用稍微不同的算法的C中的贡献解决方案。