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手工计算来检验我的假设。