Java 计算乘积a*b²;*c³。。。有效地

Java 计算乘积a*b²;*c³。。。有效地,java,math,biginteger,arbitrary-precision,Java,Math,Biginteger,Arbitrary Precision,计算乘积的最有效方法是什么 a1 b2 c3 d4 e5 假设平方运算的成本大约是乘法的一半?操作数少于100 对于乘法时间与操作数长度的平方成正比的情况(如java.math.biginger)是否也有一个简单的算法 第一个(也是唯一的)答案是完美的手术次数 有趣的是,当应用于sizablebigingers时,这一部分根本不重要。即使在没有任何优化的情况下计算abbccddddeeee也需要大约相同的时间 大部分时间都花在最终乘法上(biginger没有实现像Karatsuba、Toom–

计算乘积的最有效方法是什么

a1 b2 c3 d4 e5

假设平方运算的成本大约是乘法的一半?操作数少于100

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


第一个(也是唯一的)答案是完美的手术次数

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

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

更新
在Java8中,
BigInteger

中既有Karatsuba乘法,也有Toom-Cook乘法,我完全不知道这是否是最佳方法(尽管我认为它是渐近最优的),但您可以在
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
输入参数相乘。

As:
由于操作数大小的乘法时间是超线性的,因此保持长操作的操作数大小相似(特别是如果唯一可用的Toom Cook是Toom-2(Karatsuba))将是有利的。如果不进行全面优化,将操作数放入队列中,允许按增加(有效)长度的顺序弹出操作数,这看起来是一个不错的选择。
此外,还有一些特殊情况:0,2的幂,一个因子(否则)“平凡”的乘法(“长乘一位数乘法”,因子长度之和为线性)。
平方运算比一般乘法更简单/更快(问题建议假设½),这将建议以下策略:

  • 在预处理步骤中,计算按指数加权的尾随零数
    如果遇到0,则结果为0
  • 删除尾随零,放弃结果值1
    如果没有剩余值,结果1
  • 查找并合并多次出现的值
  • 设置允许提取“最短”号码的队列。对于每一对(数字、指数),插入将相乘的因子
  • 可选:组合“琐碎因素”(见上文)并重新插入
    我不知道该怎么办。假设长度为12的因子,其中平凡因子和初始因子的长度为1,2,…,10,11,12,…,n。最佳情况下,将1+10、2+9……与12中的7个小因子组合。将最短值相加,从12中得到8的3、6、9、12
  • 提取最短的一对因子,乘以并重新插入
    一旦只有一个数字,结果就是第一步加上零

(如果因子分解很便宜,那么就必须很早进行,才能从廉价的平方中获得最大的收益。)

看起来是一个合理的面试问题。。。基本解决方案(非最优)是简单地分别计算每个成员的幂(乘法的log2(幂))并将结果相乘…有一个
O(N log(N)^2)
算法来实现这一点(其中N是最终数字的大小)。但是您需要超越java.math.biginger来实现它。操作数的类型是什么?int?@Adam:事实上,操作数是
biginger
s,但目前我不知道有多大。
biginger没有实现像Karatsuba、Toom–Cook或FFT这样更智能的算法,所以时间是二次的
java.math.BigInteger的什么实现是这个引用/应用的?看起来这个将在大约
O(N^2)
时间内运行。这对于OP.+1来说似乎已经足够好了,也就是说,它不是渐近最优的,因为它可以在
O(N log(N)^2)
中完成,尽管使用非常难以实现的算法。在他当前的伪代码就绪的情况下,它在
O(N)
时间内运行。他的代码缓存以前的乘法,因此只执行2*
n
乘法。如果
n
是输入参数的个数,@biginger
上的Sebastian乘法不是常数时间。啊,这很有意义。我不知道这是一个限制。是的,它吸引了很多人。对于java的
biginger
,它的操作数大小可以慢到
O(N^2)