模数与Java中的双精度数

时间:2010-07-12 09:38:52

标签: java double modulus

在使用双精度时,如何使用模运算符处理Java的奇怪行为?

例如,您希望3.9 - (3.9 % 0.1)的结果为3.9(事实上,Google表示我不会疯狂),但是当我在Java中运行它时得到3.8000000000000003

我知道这是Java存储和处理方式加倍的结果,但是有办法解决它吗?

4 个答案:

答案 0 :(得分:17)

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

    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。

答案 1 :(得分:3)

来自The Java Language Specification

  

浮点的结果   余数运算由...计算   %运算符与此不同   由剩余的操作产生   IEEE 754定义的IEEE 754   余数运算计算   来自四舍五入的余数,   不是截断的分裂,所以它   行为与此类似   通常的整数余数运算符。   相反,Java编程语言   在浮点运算上定义%   行为方式类似于   整数余数的那个   操作;这可以与之比较   C库函数fmod。 IEEE   754剩余操作可能是   由库例程计算   Math.IEEEremainder。

换句话说,这是因为Java对计算余数所涉及的除法结果进行了舍入,而IEEE754则指定截断除法的答案。这种特殊情况似乎非常清楚地揭示了这种差异。

您可以使用Math.IEEEremainder获得您期望的答案:

System.out.println(3.9 - (3.9 % 0.1));
System.out.println(3.9 - Math.IEEEremainder(3.9, 0.1));

答案 2 :(得分:2)

您可以使用java.math.BigDecimal及其方法divideAndRemainder()。

答案 3 :(得分:1)

如果您知道要处理的小数位数,可以先尝试转换为整数。这只是浮点运算的经典案例。而不是3.9 % 0.1你正在做3.899 % 0.0999

之类的事情