5

我有一种情况,性能非常重要。在我的算法的核心,有一种方法可以使用两个double原语进行一些基本计算。每次运行该算法时,该方法被调用超过一千万次。

代码看起来像这样;

public int compare(double xA, double xB, double yA, double yB);

    double x = xA * xB;
    double y = yA * yB;

    double diff = x - y;

    return (diff < 0.0 ? -1 : (diff > 0.0 ? 1 : 0));

}

参数xAyA从一组中获取它们的值。这个集合可以在代码中调整。我看到巨大的(大约两倍)性能差异取决于我放入集合中的值。似乎如果集合包含 a0.1或 a 0.3,则性能会受到很大影响。将集合保持为的倍数0.5可获得最佳性能。

编译器是否优化x * 0.5x >> 1?或者这是因为0.1不能用二进制定义?

我想更好地了解这种情况,以便我可以优化它。我想这可能是一个相当困难的问题,除非有人确切知道 javac 和 jvm(在我们的例子中是热点)如何处理双乘法。

4

1 回答 1

1

只是一个夫妻几个想法:

  • 如果值是 0.5 的倍数,那么尾数中的有效位将很少,因此乘法需要更少的循环似乎是可行的。实际上,乘法的有效位似乎不是问题,因为现代处理器只需要两个周期来实现双精度(如浮点除法与浮点乘法中所述)。

    例如,我认为对于 0.5 、 1 、 2、 4 等,尾数将全为零(第一个“1”因隐含而被省略)。对于 .75、1.5、3 等,它将是 msb 中的“1”,后跟全零。而 0.1 将使用所有有效数字精度来表示,即使这样也会有一个小误差。

  • 关于返回的结果: Math.signum()有什么问题吗?我的意思是,也许这会做同样的事情:

    return Math.signum(x-y);
    
  • 如果精度不是最重要的,您可以考虑使用单精度(浮点数)。(虽然如果这意味着你要从 double 来回转换,那么它可能不值得)。

于 2012-08-01T12:10:18.513 回答