我有一个Java方法,它在一个非常紧凑的循环中重复计算以下表达式并且重复次数很多:
Math.abs(a - b) - Math.abs(c - d)
a
,b
,c
和d
是long
值,可以涵盖其类型的整个范围。它们在每次循环迭代中都是不同的,它们不满足我所知道的任何不变量。
分析器指示在此方法中花费了大部分处理器时间。虽然我将首先寻求其他优化途径,但我想知道是否有更聪明的方法来计算上述表达式。
除了手动内联Math.abs()
调用以获得非常轻微(如果有)的性能增益之外,还有什么数学技巧可以用来加速对此表达式的评估吗?
答案 0 :(得分:4)
我怀疑分析器没有给你一个真实的结果,因为它试图分析(并因此添加头部)这样一个简单的“方法”。没有配置文件,Math.abs可以转换为少量的机器代码指令,你将无法使它更快。
我建议你做一个微基准来证实这一点。我希望加载数据的成本要高出一个数量级。
long a = 10, b = 6, c = -2, d = 3;
int runs = 1000 * 1000 * 1000;
long start = System.nanoTime();
for (int i = 0; i < runs; i += 2) {
long r = Math.abs(i - a) - Math.abs(c - i);
long r2 = Math.abs(i - b) - Math.abs(d - i);
if (r + r2 < Integer.MIN_VALUE) throw new AssertionError();
}
long time = System.nanoTime() - start;
System.out.printf("Took an average of %.1f ns per abs-abs. %n", (double) time / runs);
打印
Took an average of 0.9 ns per abs-abs.
答案 1 :(得分:3)
我最终使用了这个小方法:
public static long diff(final long a, final long b, final long c, final long d) {
final long a0 = (a < b)?(b - a):(a - b);
final long a1 = (c < d)?(d - c):(c - d);
return a0 - a1;
}
我经历了可测量的性能提升 - 整个应用程序大约10-15%。我相信这主要是由于:
取消方法调用:我调用此方法一次,而不是两次调用Math.abs()
。当然,静态方法调用并不是非常昂贵,但它们仍然会产生影响。
消除了几个否定操作:这可能会被稍微增加的代码大小所抵消,但我会高兴地自欺欺人地相信它实际上有所作为
修改强>
它似乎实际上是另一种方式。明确地内联代码似乎不会影响我的微基准测试中的性能。改变计算绝对值的方式是......
答案 2 :(得分:1)
您可以随时尝试展开功能并进行手动优化,如果您没有获得更多缓存未命中,则可能会更快。
如果我展开正确,它可能是这样的:
if(a<b)
{
if(c<d)
{
r=b-a-d+c;
}
else
{
r=b-a+d-c;
}
}
else
{
if(c<d)
{
r=a-b-d+c;
}
else
{
r=a-b+d-c;
}
}
答案 3 :(得分:0)
你确定它的方法本身会导致问题吗?也许它是对这种方法的大量调用,你只是在你的探查器中看到聚合结果(如TIME_OF_METHOD_EXECUTION X NUMBER_OF_INVOCATIONS)?