Java IEEE 64位754双,值避免

lyn*_*nks 5 java floating-point double performance

我的情况表现非常重要.在我的算法的核心有一个方法,它使用两个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));

}
Run Code Online (Sandbox Code Playgroud)

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

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

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

Jav*_*ier 1

只是一个夫妻几个想法:

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

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

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

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