【发布时间】:2016-04-10 20:11:30
【问题描述】:
昨天看到一个问题问Math.pow(int,int)为什么这么慢,但是这个问题措辞不好,也没有研究,所以很快就关闭了。
我自己做了一个小测试,发现在处理整数参数时,Math.pow 方法与我自己的幼稚实现(甚至不是特别有效的实现)相比确实运行得非常慢。下面是我运行来测试的代码:
class PowerTest {
public static double myPow(int base, int exponent) {
if(base == 0) return 0;
if(exponent == 0) return 1;
int absExponent = (exponent < 0)? exponent * -1 : exponent;
double result = base;
for(int i = 1; i < absExponent; i++) {
result *= base;
}
if(exponent < 1) result = 1 / result;
return result;
}
public static void main(String args[]) {
long startTime, endTime;
startTime = System.nanoTime();
for(int i = 0; i < 5000000; i++) {
Math.pow(2,2);
}
endTime = System.nanoTime();
System.out.printf("Math.pow took %d milliseconds.\n", (endTime - startTime) / 1000000);
startTime = System.nanoTime();
for(int i = 0; i < 5000000; i++) {
myPow(2,2);
}
endTime = System.nanoTime();
System.out.printf("myPow took %d milliseconds.\n", (endTime - startTime) / 1000000);
}
}
在我的计算机(intel x86_64 cpu 上的 Linux)上,输出几乎总是报告 Math.pow 花了 10 毫秒,而 myPow 花了 2 毫秒。这偶尔会在这里或那里波动一毫秒,但 Math.pow 的平均运行速度约为 5 倍。
我做了一些研究,根据grepcode 的说法,Math.pow 只提供了一个类型签名为(double, double) 的方法,并将其推迟到作为本机方法调用的StrictMath.pow 方法。
Math 库仅提供处理双打的pow 函数这一事实似乎表明可能回答了这个问题。显然,与只处理整数的算法相比,必须处理 double 类型的基数或指数的可能性的幂算法将花费更长的时间来执行。然而,最后,它归结为依赖于架构的本机代码(它几乎总是比 JVM 字节码运行得更快,在我的例子中可能是 C 或汇编)。 似乎在这个级别上会进行优化以检查数据类型并尽可能运行更简单的算法。
鉴于此信息,为什么在给定整数参数时,本机 Math.pow 方法始终比我未优化和幼稚的 myPow 方法运行得慢得多?
【问题讨论】:
-
我对此发表评论:int absExponent = (exponent
-
-
由于您的实现在指数上使用循环,因此计算平方是一个非常有偏见的基准。为什么不在 2⁸ 上同时尝试这两种方法:) (当然,您可以使用不那么简单的算法做得更好,但即便如此,2¹⁵ 可能会显示不同的结果。)
标签: java algorithm performance