有效地计算产品a * b ** 2 * c ** 3 ....

时间:2012-10-25 21:21:44

标签: java math biginteger arbitrary-precision

计算产品的最有效方法是什么

  

1 b 2 c 3 d 4 e 5 ...

假设平方成本大约是乘法的一半?操作数的数量小于100。

对于乘法时间与操作数长度的平方成正比的情况(与java.math.BigInteger一样),是否还有一个简单的算法?


第一个(也是唯一的)答案是完美的w.r.t.操作次数。

有趣的是,当应用于相当大的BigInteger时,这部分根本不重要。即使在没有任何优化的情况下计算 abbcccddddeeeee 也需要大约相同的时间。

大部分时间花在最后的乘法上(BigInteger没有实现像Karatsuba,Toom-Cook或FFT这样的智能算法,所以时间是二次的)。重要的是确保中间被乘数大约是相同的大小,即给定大小相同的数量 p,q,r,s 计算(pq)(rs)通常比((pq)r)s 更快。对于几十个操作数,速度比似乎约为1:2。

2 个答案:

答案 0 :(得分:5)

我绝对不知道这是否是最佳方法(尽管我认为它是渐近最优的),但你可以在O(N)次乘法中完成所有这些。您将a * b^2 * c^3的参数分组为:c * (c*b) * (c*b*a)。在伪代码中:

result = 1
accum = 1
for i in 0 .. arguments:
  accum = accum * arg[n-i]
  result = result * accum

我认为它是渐近最优的,因为你必须使用N-1乘法来乘以N输入参数。

答案 1 :(得分:1)

mentioned in the Oct 26 '12 edit
由于操作数大小的乘法时间是超线性的,因此将长操作的操作数大小保持相似是有利的(特别是如果唯一可用的Toom-Cook是toom-2(Karatsuba))。如果不进行完全优化,将操作数放在队列中以允许按长度增加(显着)的顺序弹出它们,这似乎是对臀部的一个很好的尝试。
再说一次,有一些特殊情况:0,2的乘方,其中一个因子是(否则)“平凡”的(“长乘一位数乘法”,因子长度的总和是线性的)。
并且平方比普通乘法更简单/更快(问题建议假设½),这将建议以下策略:

  • 在预处理步骤中,计算由指数加权的尾随零
    如果遇到0,结果为0
  • 删除尾随零,丢弃结果值1
    如果没有剩余值,结果为
  • 查找并合并多次出现的值
  • 设置一个队列,以允许提取“最短”号码。对于每一对(数字,指数),插入因子exponentiation by squaring将成倍
  • 可选:结合“琐碎的因素”(请参见上文)并重新插入
    不知道如何去做。说出长度为12的因子,其中琐碎的,初始因子为长度1,2,…,10,11,12,…,n。最佳地,您将1 + 10、2 + 9,…组合为12中的7个琐碎因素。最短组合会得到12中的8的3、6、9、12。
  • 提取最短的因子对,相乘并重新插入
    一旦只有一个数字,结果就是将第一步中的零加在上面

(如果分解成本很低,那么它就必须很早进行下去,才能从廉价平方中获得最大收益。)