模数与Java中的双精度数

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

例如,你会期望3.9 - (3.9 % 0.1)的结果为3.9 - (3.9 % 0.1)事实上, 谷歌说我不会疯狂),但是当我用Java运行时,我得到3.8000000000000003

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

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

  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。

来自Java语言规范 :

由%运算符计算的浮点余数运算的结果与由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)); 

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

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