查找2和5因子的最快算法

时间:2015-06-28 13:01:23

标签: algorithm division prime-factoring

我已经阅读了这个问题:Which is the fastest algorithm to find prime numbers?,但我只想对25素数这样做。

例如,数字42000被分解为:

  

2 4 •3 1 5 3 •7 1

我只对在此示例中找到2543的权力感兴趣。

我天真的方法是先后除以2,其余为0,然后相继除以5,其余为0

成功分裂的数量(零余数)是2和5的幂。

这涉及执行(x + y + 2)分区,其中x是2的幂,y是5的幂。

是否有更快的算法来查找2和5的幂?

4 个答案:

答案 0 :(得分:1)

在谈话之后,我认为你的想法是最快的方式,但有一个例外:

分部(在大多数情况下)很贵。另一方面,检查数字的最后一位数(通常是?)会更快,所以我会在分割之前检查最后一位数字(0/50/2/4/6/8)。

答案 1 :(得分:1)

我的基础是OP:

  

我的库是用PHP编写的,数字实际上是作为字符串存储在基数10中的。这确实不是最有效的,但这是在语言的技术限制内最有效的。

如果你致力于php-in-php,那么与实际的通用重复模数和除法相比,下面的伪代码将加快速度:

while the string ends in 0, but is not 0
  chop a zero off the end,
  increment ctr2 and ctr5
switch repeatedly depending on the last digit:
  if it is a 5,
     divide it by 5
     increment ctr5
  if it is 2, 4, 6, 8,
     divide it by 2
     increment ctr2
  otherwise
     you have finished

这不需要任何模数运算,并且您可以比通用长数除法更便宜地实现5分频和2分频。

另一方面,如果你想要表现,使用无限大小整数的字符串表示就是自杀。使用 gmp (其中包含php library)进行数学运算,并仅在必要时转换为字符串。

修改

使用以下伪代码可以获得额外的效率(并简化操作):

if the string is zero, terminate early
while the last non-zero character of the string is a '5',
   add the string to itself
   decrement ctr2
count the '0's at the end of the string into a ctr0
chop off ctr0 zeros from the string
ctr2 += ctr0
ctr5 += ctr0
while the last digit is 2, 4, 6, 8
   divide the string by 2
   increment ctr2

一次砍掉多个0比循环更好。并且mul2在速度方面胜过div5(可以通过添加一次数来实现)。

答案 2 :(得分:0)

我认为你的算法将是最快的。但我有几点建议。

一种替代方案是基于最大公约数。取输入数字的gcd,最小功率2大于输入数字;这将给你所有的因素2.除以gcd,然后用5重复相同的操作;这将给你所有因素5.再次除以gcd,其余部分告诉你是否还有其他因素。

另一种选择是基于二分搜索。将输入数字的二进制表示分成两半;如果右半边是0,向左移动,否则向右移动。一旦你有2的因子,除法,然后使用5的幂来对剩余部分应用相同的算法。

我会留给您实施和计算这些算法的时间。但我的直觉是重复分裂将很难被击败。

我刚刚读到你的评论,你的输入数字存储在基数10中。在这种情况下,只要余数为0,重复除以10;给出2和5的因子。然后将算法应用于减少的数字。

答案 3 :(得分:0)

如果您有十亿位数字,除非确实需要,否则您不希望对其进行分割。如果你没有理由相信它在1 ^ 2 ^ 1000的数字中可以被2 ^ 1000整除,那么使用更快的测试只看最后几位是有意义的。您可以通过查看最后一位数字来判断一个数字是否可以被2整除,通过查看最后两位数字是否可以被4整除,通过查看最后n位数字可以看出2 ^ n。类似地,您可以通过查看最后一位数字来判断一个数字是否可被5整除,通过查看最后两位数字是否可以被25整除,通过查看最后n位数字可以将其除数为5 ^ n。

我建议您首先计算并删除尾随的0,然后从最后一位开始判断您是否正在测试2的幂(最后一个数字2,4,6或8)或5的幂(最后一个数字5) 。

如果您正在测试2的幂,那么取最后的2个,4个,8个,16个...... 2 ^ i个数字,并将其乘以25,625,... 5 ^ 2 ^ i,计数尾随0到2 ^ i(但不超过)。如果你得到少于2 ^ i尾随0,那么停止。

如果您正在测试5的幂,那么取最后的2个,4个,8个,16个...... 2 ^ i个数字,并将其乘以4,16,...... 2 ^ 2 ^ i,计数尾随0到2 ^ i(但不超过)。如果少于2 ^ i尾随0,则停止。

例如,假设您分析的数字是283,795,456。乘以56乘25,你得到1400,其中有2个尾随0,继续。乘以5,456乘625,得到3,410,000,其中有4个尾随0,继续。乘以83,795,456乘以5 ^ 8 = 390,625,得到32,732,600,000,000,其中有8个尾随0,继续。乘以283,795,456乘以5 ^ 16得到43,303,750,000,000,000,000,其中只有13个尾随0。那个小于16,所以停止,素数因子化中2的幂是2 ^ 13。

我希望对于更大的乘法,你实现了一个n log n算法来乘以n位数,但即使你不是,这种技术应该胜过任何涉及典型大数的除法。

假设每个n位数字具有相同的可能性,让我们看一下各种算法的平均时间复杂度。

两个n位数的加或减需要θ(n)步。

将n位数除以5之类的小数字需要theta(n)步。除以基数是O(1)。

将n位数除以另一个大数,使用FFT得到theta(n log n)步,或者通过朴素算法得到theta(n ^ 2)。乘法也是如此。

将基数10重复除以2的算法具有 theta(n)的平均病例时间复杂度:第一次除法需要theta(n)时间,平均而言,只需做O(1)分裂。

计算具有至少n位数的2的大功率通过重复平方获得theta(n log n),或通过简单乘法获得theta(n ^ 2)。执行Euclid算法来计算GCD需要采用θ(n)步的平均值。虽然划分采用theta(n log n)时间,但大多数步骤可以作为重复减法完成,并且只需要花费n(n)时间来完成这些步骤。以这种方式执行Euclid算法需要O(n ^ 2 log log n)。其他改进可能会将其降低到 theta(n ^ 2)

在执行更昂贵的计算之前,将最后一位数字的可除性检查为2或5是好的,但这只会导致因子不断改进。在此之后应用原始算法仍然需要平均 theta(n)步骤。

通过2 ^ d或5 ^ d检查可分割性的最后d个数字需要O(d ^ 2)时间,O(d log d)和FFT。当d很小时,我们很可能只需要这样做。可被2 ^ d整除的n位数的分数是1/2 ^ d。因此,在这些检查上花费的平均时间是O(sum(d ^ 2/2 ^ d)),并且该和与n无关,因此平均需要 theta(1)时间。当您使用最后一位数字来检查可分性时,通常不必对接近n位的数字进行任何操作。