Java 十进制算术表达式的意外结果

Java 十进制算术表达式的意外结果,java,Java,我有一些带算术表达式的业务逻辑,它们的结果如下 (10.0 * 20.58)/1.0=205.7999..98 (6.0 * 37.9)/1.0=227.3999..98 (5.0 * 50.0)/1.0=250.0 (10.0 * 37.9)/1.0=379.0 但预期的结果并不乐观 (10.0 * 20.58)/1.0=205.8 (6.0 * 37.9)/1.0=227.4 (5.0 * 50.0)/1.0=250.0 (10.0 * 37.9)/1.0=379.0 我不清楚我们为什么

我有一些带算术表达式的业务逻辑,它们的结果如下

(10.0 * 20.58)/1.0=205.7999..98
(6.0 * 37.9)/1.0=227.3999..98
(5.0 * 50.0)/1.0=250.0
(10.0 * 37.9)/1.0=379.0
但预期的结果并不乐观

(10.0 * 20.58)/1.0=205.8
(6.0 * 37.9)/1.0=227.4
(5.0 * 50.0)/1.0=250.0
(10.0 * 37.9)/1.0=379.0
我不清楚我们为什么会得到.999..98分数部分?由于我的equals比较失败,所以业务逻辑也失败了。对于我们正在使用的少数情况

amt = (double)Math.round(orderAmt*100000)/100000;
但这不可能在每一个有双算术表达式的地方都这样做


我想知道为什么我们会随机得到这样的结果,有没有可能将结果四舍五入到小数点后5位而不是四舍五入?

您可以使用
BigDecimal
进行四舍五入

BigDecimal bd = new BigDecimal((10.0 * 20.58)/1.0) ;
bd = bd.setScale(4, RoundingMode.UP);
使用静态方法

public static double round(double value, int digits) {
    BigDecimal bd = new BigDecimal(value);
    return bd.setScale(digits, RoundingMode.UP).doubleValue();
}
RoundingMode
具有:

RoundingMode.UP;
RoundingMode.DOWN;
RoundingMode.HALF_DOWN;
RoundingMode.HALF_EVEN;

使用
float
代替
double

输出

205.8


您可能希望使用
double
并按如下方式取整:

    double roundingPlaces = 10.0;//use 10.0 for single decimal digit rounding
    double a1 = 10.0;
    double b1 = 20.58;
    double c1 = 1.0;
    System.out.println(Math.round((a1*b1*roundingPlaces)/c1)/roundingPlaces);
这是205.8

    float fa1 = (float) 10.0;
    float fb1 = (float)20.58;
    float fc1 = (float)1.0;
    System.out.println(fa1*fb1/fc1);    

这也会打印205.8,基本问题是

System.out.println(10.0 * 20.58);
印刷品

205.79999999999998
20580
由于
20.58中的表示错误,存在较小的舍入误差

你要么需要

  • 比较前先对结果进行四舍五入
  • 使用允许某些错误的比较
  • 使用BigDecimal(在大多数情况下,这是过度终止)
  • 使用美分而不是美元,即使用固定精度的
    int
    long
在最后一种情况下,相同的操作将读取

System.out.println(10 * 2058);
印刷品

205.79999999999998
20580

其中,这是作为其固定精度所需值的100倍,例如,美分而不是美元。

基数为10时,有些分数无法用有限位数精确表示,例如1/3=0.33333

基数2也是一样的,除了产生这种结果的除数不是我们习惯的除数,例如,对于20.58,也就是2058/100,情况就是这样

在内部,double和float与位(非数字)一起存储,因此double或float的确切值无法存储在计算机内存中。每次使用此值执行操作时,由于近似值,会出现一个小的偏移,当转换回十进制格式以进行打印时,该偏移会变得可见

在进行精度很重要的计算时,必须注意这一点

因此,您有两种解决方案:

  • 以十进制类型存储所有数字,并使用它执行所有计算。这将达到精度,但性能价格
  • 您还可以使用double或float保留所有计算,并仅为打印结果使用固定位数格式化

您没有对双精度
使用十进制算法。我建议你告诉自己双精度的实际值是什么。请参阅and或RoundingMode.HALF_甚至将其四舍五入到最接近的值很好的解释!谢谢我们在哪里可以读到关于双精度浮点数和位存储的更多细节?有链接要通过吗?很抱歉,我没有第三方参考;=)。我自己在遇到类似问题时发现了这一点。我第一次想到这一点时,我用基数2手工计算来检验我的假设。