代码之家  ›  专栏  ›  技术社区  ›  Andy

爪哇双模模量

  •  12
  • Andy  · 技术社区  · 16 年前

    当使用双打时,如何处理模数运算符的Java怪异行为?

    例如,您希望 3.9 - (3.9 % 0.1) 成为 3.9 (事实上, Google 说我不会发疯,但是当我在Java中运行它时 3.8000000000000003 .

    我知道这是Java商店和流程如何翻番的结果,但是有没有办法解决它呢?

    4 回复  |  直到 11 年前
        1
  •  17
  •   Aaron Digulla    16 年前

    如果需要精确的结果,请使用精确的类型:

        double val = 3.9 - (3.9 % 0.1);
        System.out.println(val); // 3.8000000000000003
    
        BigDecimal x = new BigDecimal( "3.9" );
        BigDecimal bdVal = x.subtract( x.remainder( new BigDecimal( "0.1" ) ) );
        System.out.println(bdVal); // 3.9
    

    为什么是3.8000…003?因为Java使用了FPU来计算结果。3.9不可能精确地存储在IEEE双精度符号中,所以它存储了3.89999…相反。3.8999%0.01得到0.09999…因此,结果略大于3.8。

        2
  •  3
  •   MAK    16 年前

    从 The Java Language Specification :

    浮点运算的结果 剩余操作由 %运算符与该运算符不同 由剩余操作生成 由IEEE 754定义。IEEE 754 剩余操作计算 舍入除法的余数, 不是截断除法,因此 行为与 常用的整数余数运算符。 相反,Java编程语言 定义浮点运算的百分比 以类似于 整数余数的余数 运算符;这可以与 C库函数fmod。IEEE 754剩余操作可能是 由库例程计算 数学.ieeeremander.

    换言之,这是由于Java在计算余数时所涉及的除法的结果,IEEE74规定截除该除法的答案。这个特殊的案例似乎很清楚地揭示了这种差异。

    您可以使用math.ieeeremander获得预期的答案:

    System.out.println(3.9 - (3.9 % 0.1));
    System.out.println(3.9 - Math.IEEEremainder(3.9, 0.1));
    
        3
  •  2
  •   Sjoerd    11 年前

    可以使用java.math.bigdecimal及其方法 divideAndRemainder ()

        4
  •  1
  •   Wolph    16 年前

    如果你知道你要处理的小数的数量,你可以尝试先转换成整数。这只是一个典型的浮点不精确的例子。而不是做 3.9 % 0.1 你在做类似的事情 3.899 % 0.0999