2012-08-01 36 views
5

我有一种情况,性能是非常重要的。在我的算法的核心,有一个方法可以用两个基本元素进行一些基本的计算。该算法在每次运行中被称为超过一千万次。Java IEEE 64位754双倍值,以避免

代码看起来像这样;

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采取从一组其值。这个集合可以在代码中调整。我看到了巨大的(大约两倍)性能差异,这取决于我放入该组的价值。看起来如果该集合包含0.10.3,则表现会受到重创。保持设置为0.5的倍数可以获得最佳性能。

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

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

+0

您确定性能差异直接在此例程中,而不是更改xA和yA导致返回不同结果的结果,从而更改此例程返回后执行的内容? – 2012-08-01 18:54:56

+0

您可以通过删除该行并用'return x y?替换返回来消除减法。 1:0;'。 – 2012-08-01 18:57:02

+0

如果可用的调整延伸到可以用p/q和1代替xA和yA的值p和q,那么可以消除乘法,从而留下'double x = xA * xB; double y = yB;'(取决于通常的浮点舍入问题)。 – 2012-08-01 18:59:40

回答

1

只是夫妇一些想法:

  • 如果值倍数为0.5,那么就会出现在mantissa几个显著位,所以它似乎是可行的乘法花费更少的圈子中。实际上乘法的有效位似乎不成问题,因为现代处理器只需要两个周期的双倍(如Floating point division vs floating point multiplication中所述)。

    E.g.我用0.5,1,2,4等等来表示尾数将全部为零(首先“1”因隐式而忽略)。对于.75,1.5,3等,它将是m.s.b中的“1”。其次是全零。而0.1会使用所有的有效精度来表示,甚至有一个小错误。

  • 关于返回的结果:Math.signum()是否有任何问题?我的意思是,这也许会做同样的:

    return Math.signum(x-y); 
    
  • 如果precission是不是最重要,你可以考虑使用单precission(浮动)。 (但如果这意味着你将要从双倍来回转换,那么它可能不值得)。

+1

是的,这是可行的,但是这意味着我会为了回报而投入int,因此我避免了这种情况。 – lynks 2012-08-01 12:21:55