Math.abs(a - b)的更快实现 - Math.abs(c - d)?

时间:2012-01-19 10:47:18

标签: java algorithm optimization

我有一个Java方法,它在一个非常紧凑的循环中重复计算以下表达式并且重复次数很多:

Math.abs(a - b) - Math.abs(c - d)

abcdlong值,可以涵盖其类型的整个范围。它们在每次循环迭代中都是不同的,它们不满足我所知道的任何不变量。

分析器指示在此方法中花费了大部分处理器时间。虽然我首先寻求其他优化途径,但我想知道是否有更聪明的方法来计算上述表达式。

除了手动内联Math.abs()调用以获得非常轻微(如果有)的性能增益之外,还有什么数学技巧可以用来加速对此表达式的评估吗?

4 个答案:

答案 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)?