6

我对 pow(exponent) 方法做了一些测试。不幸的是,我的数学能力不足以处理以下问题。

我正在使用这段代码:

BigInteger.valueOf(2).pow(var);

结果:

  • 变量 | 以毫秒为单位的时间
  • 2000000 | 11450
  • 2500000 | 12471
  • 3000000 | 22379
  • 3500000 | 32147
  • 4000000 | 46270
  • 4500000 | 31459
  • 5000000 | 49922

看?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);
    }
4

3 回答 3

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 毫秒
1048576: 0010000000000000000000000 // 6209 毫秒
于 2010-05-28T22:47:45.733 回答
1

只是一个猜测:

指数逐位处理,如果最低有效位为 1,则完成额外的工作。

如果 L 是指数中的位数,A 是 1 的位数,t1 是处理公共部分的时间,t2 是 LSbit 为 1 时的附加时间处理

那么运行时间将是

L t1 + A t2

或者时间取决于二进制表示中 1 的数量。

现在写一个小程序来验证我的理论......

于 2010-05-28T22:39:18.647 回答
1

我不确定你运行了多少次计时。正如一些评论者指出的那样,您需要多次为操作计时才能获得良好的结果(而且他们仍然可能是错误的)。

假设你已经很好地计时了,请记住在数学中有很多捷径可以走。您不必执行 5*5*5*5*5*5 的操作来计算 5^6。

这是一种更快的方法。 http://en.wikipedia.org/wiki/Exponentiation_by_squaring

于 2010-05-28T22:40:39.453 回答