一个 Java 的问题,我不理解

48 天前
 sisi041
public static void main(String[] args) {
Double a=-0.57;
a=a*100;
System.out.println(a);
}

为啥打印出来的不是 -57 ?
2441 次点击
所在节点    Java
16 条回复
cococaoliug
48 天前
因为 double 是整型,你得用 float 浮点数
rimwindy
48 天前
```
jshell> Double a = -0.57; System.out.println(a * 100);
a ==> -0.57
-56.99999999999999
```

你指的是浮点数溢出吗?正如十进制无法精确表示 1/3 、1/6 、1/7 、1/9 一样,因为二进制中唯一的质因数是 2 ,所以只能精确表示 1/2 、1/4 、1/8 这样的数。
wenhuibrave
48 天前
java 中的 double 是一个 64 位的 IEEE 754 浮点数,这使得它在很多情况下足够精确,但对于某些数值,例如 0.57 ,就会出现这种舍入误差。
wenhuibrave
48 天前
想要输出-57 ,可以用 BigDecimal 表示,避免传统的浮点数舍入误差。
gitrebase
48 天前
Curtion
48 天前


因为 IEEE 754
sisi041
48 天前
@wenhuibrave 如果不用 BigDecimal , 我 Math.round 一下,是不是也可以解决?
me1onsoda
48 天前
@cococaoliug double 是双精度浮点型。。
hapeman
48 天前
计算机实际存储是通过二进制进行的,所以存储非整型的数据时允许存在一定的误差
所以你输入的其实是一个近似于-0.57 的二进制数,你*100 之后就出现了丢失经度的情况
这一情况可以通过使用 BigDecimal 解决,需要注意的是在使用 BigDecimal 的构造函数初始化一个值的时候使用 String 类型而不是 Double ,使用 Double 也会丢失精度
在设计金额之类字段的时候一定不能使用 Double 、Float 等类型,请使用 BigDecimal
andrewpsy
48 天前
对待楼主这种情况:
1. 如果有 BigDecimal 这类带精度的数值 type 那必须用。
2. 没有精度 type 的话尽量不用或少用除法。比如想把 2600 秒换算成分钟,尽量一直用秒甚至毫秒表示,这样不涉及除法。实在需要除法(想得到小时为单位的答案)就尽量整合除法只除一次。比如把 2600 秒/60/60=?小时变成 2600/(60*60),这时 round 只出现一次除法误差。
nitmali
48 天前
System.out.println(0.1 + 0.2);
githmb
48 天前
balalaFairty
48 天前
@sisi041 『如果不用 BigDecimal , 我 Math.round 一下,是不是也可以解决?』不能应对所有情况,不推荐这么做。如果你的应用场景里小数点只有 2 位,不涉及与其他浮点数的运算,并且下限不超过 [2^63-1, -2^63],你可以底层存储的时候改成 long 来存储和计算,最后展示输出的时候再除以 100 ,这样可以在大部分场景下避免使用 BigDecimal 。
sisi041
47 天前
@balalaFairty 明白了,多谢
vituralfuture
47 天前
复习一下计算机组成原理就明白了,典型的浮点数误差,另外比较两个浮点数相等也一般不用==,而是判断两者差值是否足够小
hkdcl
45 天前
@cococaoliug 我支持你,op 太菜了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1025883

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX