Java JVM上的浮点操作会在所有平台上产生相同的结果吗?

Java JVM上的浮点操作会在所有平台上产生相同的结果吗?,java,floating-point,Java,Floating Point,我在多台机器上运行的应用程序中使用Java,所有机器都需要获得相同的数学运算结果。使用Java的浮点原语安全吗?或者我应该只使用定点数学库吗?一般不使用。但是,您可以使用: 在FP严格表达式中,所有中间值必须是浮点值集或双值集的元素,这意味着所有FP严格表达式的结果必须是IEEE 754算术在使用单格式和双格式表示的操作数上预测的结果 在非FP严格的表达式中,允许实现使用扩展的指数范围来表示中间结果;粗略地说,净效果是,在独占使用浮点值集或双值集可能导致溢出或下溢的情况下,计算可能会产生“正确答

我在多台机器上运行的应用程序中使用Java,所有机器都需要获得相同的数学运算结果。使用Java的浮点原语安全吗?或者我应该只使用定点数学库吗?

一般不使用。但是,您可以使用:

在FP严格表达式中,所有中间值必须是浮点值集或双值集的元素,这意味着所有FP严格表达式的结果必须是IEEE 754算术在使用单格式和双格式表示的操作数上预测的结果

在非FP严格的表达式中,允许实现使用扩展的指数范围来表示中间结果;粗略地说,净效果是,在独占使用浮点值集或双值集可能导致溢出或下溢的情况下,计算可能会产生“正确答案”


除了strictfp,还有一个要求,即对于超越函数和其他函数,结果是可预测的。

JVM应该一致地实现IEEE规范,并且该规范非常技术和精确。浮点原语float和double在所有平台上都是相同的

区别仅在于对中间结果的处理,虚拟机实现可以使用浮点扩展指数和双扩展指数格式,同时在同一执行帧内计算包含局部变量的表达式

因此,如果您有如下代码:

double d1 = 0.342;
double d2 = 1.328479;
double d3 = 4.99384728796;
System.out.println(d1 * d2 / d3);
这不是在strictfp上下文中,可能在运行时不同JVM之间存在差异。这是因为在表达式d1*d2/d3的计算中,在表达式“中间结果”/d3中使用了d1*d2的中间结果,JVM可能使用浮点扩展指数和双扩展指数格式来存储“中间结果”

为了避免这个问题,您可以使用strictfp或StrictMath,就像其他人在这里回答的那样,或者避免在表达式中使用中间结果。一种方法是在堆上存储任何中间结果。例如:

class MyClass {
    static double d1 = 0.342;
    static double d2 = 1.328479;
    static double d3 = 4.99384728796;
    static double intermediate_result = 0d;
    public static void main(String[] args) {
        intermediate_result = d1 * d2;
        System.out.println(intermediate_result / d3);
    }
}

不,这不安全。使用
BigDecimal
或者一个数学库来帮助您解决这个问题。为什么您需要在所有机器上得到完全相同的结果?你在做什么类型的计算?可能重复的网络游戏相同的游戏模型在每台机器上运行,输入通过网络发送,然后输入到模型中,为了使游戏保持同步,那么每个数学运算必须是相同的。类似的游戏在使用浮点运算时也遇到了问题……为什么要使用本质上不精确的东西(浮点)来实现需要在分布式框架上进行严格同步的东西?您是否应该考虑您的实现,而不是试图让浮点值做它不打算做的事情?+1用于数学。请注意,尽管Math中的大多数方法似乎只是简单地委托给StrictMath,但其中许多方法在运行时被JVM内部函数悄悄地替换。内部函数是特定于平台的。@ntoskrnl你能给我指一个参考或进一步的阅读吗?@dimo414这个问题回答得比我能回答得更好:你确定没有
strictfp
会使打印结果与你的示例中的d1、d2和d3的特定值不同吗?根据Jon Skeet回答中引用的段落,结果必须与d1、d2和d3这些值的
strictfp
结果相同,因为在这一特定计算中不会出现下溢或溢出。换句话说,Jon回答中的段落只提到扩展指数范围,而不是“扩展精度”@PascalCuoq我使用上述示例代码的目的仅仅是演示中间结果是什么,以及如何通过控制VM如何处理它们来避免副作用。为了回答您的问题,没有,在选择示例中d1 d2 d3的特定值时没有太多的考虑或关注。就我所能验证的而言,我所拥有的虚拟机中没有一台支持IEEE 754单扩展和双扩展格式,因此我无法在实际操作中显示这种效果。@PascalCuoq我还删除了对“扩展精度”的引用,感谢您指出,如果我声明我的主方法strictfp,整个程序应该正常工作吗?还是每个方法或表达式都必须声明为strictfp?@Eamonn:我不能说我自己使用过strictfp,但我相信你需要在每个方法上都这样做。