我对pow(指数)方法做了一些测试。不幸的是,我的数学技能不足以解决以下问题。
我正在使用此代码:
BigInteger.valueOf(2).pow(var);
结果:
请参阅? 2,500,000指数的计算速度几乎与2,000,000一样快。 4,500,000的计算速度比4,000,000快得多。
为什么?
为了给你一些帮助,这里是BigInteger.pow(exponent)的原始实现:
public BigInteger pow(int exponent) {
if (exponent < 0)
throw new ArithmeticException("Negative exponent");
if (signum==0)
return (exponent==0 ? ONE : this);
// Perform exponentiation using repeated squaring trick
int newSign = (signum<0 && (exponent&1)==1 ? -1 : 1);
int[] baseToPow2 = this.mag;
int[] result = {1};
while (exponent != 0) {
if ((exponent & 1)==1) {
result = multiplyToLen(result, result.length,
baseToPow2, baseToPow2.length, null);
result = trustedStripLeadingZeroInts(result);
}
if ((exponent >>>= 1) != 0) {
baseToPow2 = squareToLen(baseToPow2, baseToPow2.length, null);
baseToPow2 = trustedStripLeadingZeroInts(baseToPow2);
}
}
return new BigInteger(result, newSign);
}
答案 0 :(得分:9)
该算法使用重复平方(squareToLen
)和乘法(multiplyToLen
)。这些操作的运行时间取决于所涉及的数字的大小。在计算结束时,大数字的乘法比开始时的数字要贵得多。
乘法仅在此条件为真时执行:((exponent & 1)==1)
。平方运算的数量取决于数字中的位数(不包括前导零),但只有设置为1的位才需要乘法。通过查看二进制文件,可以更容易地看到所需的操作代表数字:
2000000: 0000111101000010010000000 2500000: 0001001100010010110100000 3000000: 0001011011100011011000000 3500000: 0001101010110011111100000 4000000: 0001111010000100100000000 4500000: 0010001001010101000100000 5000000: 0010011000100101101000000
请注意,2.5M和4.5M是幸运的,因为它们设置的高位比周围的数字少。下次发生这种情况的时间是8.5M:
8000000: 0011110100001001000000000 8500000: 0100000011011001100100000 9000000: 0100010010101010001000000
甜蜜点是2的精确力量。
1048575: 0001111111111111111111111 // 16408 ms 1048576: 0010000000000000000000000 // 6209 ms
答案 1 :(得分:1)
只是一个猜测:
指数逐位处理,如果最低有效位为1,则完成另外的工作。
如果L是指数中的位数 和A的位数为1 和t1处理公共部分的时间 和t2当LSbit为1时的附加时间处理
然后运行时间
L t1 + A t2
或时间取决于二进制表示中的1的数量。
现在写一个小程序来验证我的理论......
答案 2 :(得分:1)
我不确定你有多少次运行你的计时。正如一些评论者指出的那样,你需要多次操作时间才能获得好的结果(而且它们仍然可能是错误的)。
假设你有好的时间,请记住在数学中可以使用很多快捷方式。您不必进行操作5 * 5 * 5 * 5 * 5 * 5来计算5 ^ 6。
这是一种更快速地完成任务的方法。 http://en.wikipedia.org/wiki/Exponentiation_by_squaring