为什么1.0 - 0.7 != 0.3?????

Java代码   收藏代码
  1. public static void main(String[] args) {  
  2.     System.out.println(1.0 - 0.1);  
  3.     System.out.println(1.0 - 0.2);  
  4.     System.out.println(1.0 - 0.3);  
  5.     System.out.println(1.0 - 0.4);  
  6.     System.out.println(1.0 - 0.5);  
  7.     System.out.println(1.0 - 0.6);  
  8.     System.out.println(1.0 - 0.7);  
  9.     System.out.println(1.0 - 0.8);  
  10.     System.out.println(1.0 - 0.9);  
  11.     System.out.println(1.0 - 1.0);  
  12. }  


最后输出的结果为神马是 

Java代码   收藏代码
  1. 0.9  
  2. 0.8  
  3. 0.7  
  4. 0.6  
  5. 0.5  
  6. 0.4  
  7. 0.30000000000000004  
  8. 0.19999999999999996  
  9. 0.09999999999999998  
  10. 0.0  


为什么呢? 

简单的说,问题处在" IEEE 754 floating-point arithmetic ",虽然在java是遵循这个规则的,但是java语言的实现,并不是使用小数点或者十进制来表示数字,相反,它是采用分数和指数来表示,而且是
引用
uses binary fractions and exponents to represent
使用二进制的,我们可以举个例子: 

Java代码   收藏代码
  1. 0.5 = 1/2  
  2. 0.75 = 1/2 + 1/(2^2)  
  3. 0.85 = 1/2 + 1/(2^2) + 1/(2^3)  
  4. 0.1 = 1/(2^4) + 1/(2^5) + 1/(2^8) + ...  


注意,0.1只能是无限循环下去的,这就意味着0.1在java里面不能够准确的用浮点数来表示,也就造成了浮点数运算上面的误差。 

举个例子: 

Java代码   收藏代码
  1. if (0.1 + 0.1 + 0.1 != 0.3)  
  2.     System.out.println("0.1 + 0.1 + 0.1 is not equal with 0.3");  
  3. else  
  4.     System.out.println("0.1 + 0.1 + 0.1 is equal to 0.3");  


每个人都知道,0.1 + 0.1 + 0.1 == 0.3,但是在java的实际结果却不是这样。 

更深入的话  

有人会问,为什么 
Java代码   收藏代码
  1. System.out.println(0.1f);  

输出的还是0.1呢? 
因为在源代码里面println调用的是Float#toString(float),最终的实现是在 
Java代码   收藏代码
  1. public static String toString(float f) {  
  2.     return new FloatingDecimal(f).toJavaFormatString();  
  3. }  

有兴趣的童鞋可以去阅读源代码,FloatingDecimal帮你做了很多事情。 

这也牵涉出另外一个话题,如何避免上面出现的问题, 

对的,就是 BigDecimal ,关于BigDecimal,我相信你们在api上面会找到更多的答案。 

题外话  

用 
BigDecimal(java.lang.String) 
不要用 
BigDecimal(double) or BigDecimal(float) 

为什么呢?API上面写的很清楚了 
引用
The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding. 

所以 
Java代码   收藏代码
  1. System.out.println(new BigDecimal(0.1f));  
  2. System.out.println(new BigDecimal("0.1"));  
  3. System.out.println(0.1f);  

结果是不一样的 

更加更加更加深入的话  
Java代码   收藏代码
  1. if (0.1f + 0.1f + 0.1f != 0.3f)  
  2.     System.out.println("0.1 + 0.1 + 0.1 is not equal to 0.3");  
  3. else  
  4.     System.out.println("0.1 + 0.1 + 0.1 is equal to 0.3");  
  5.   
  6. if (0.1 + 0.1 != 0.2)  
  7.     System.out.println("0.1 + 0.1 is not equal to 0.2");  
  8. else  
  9.     System.out.println("0.1 + 0.1 is equal to 0.2");  


为何上面两串代码输出不一样? 为何0.3d就不能用3个0.1d相加,而0.2d就可以用2个0.1d相加呢 ? 

原因的话,自己看下面的输出了 
Java代码   收藏代码
  1. System.out.println(new BigDecimal(0.2d));  
  2. System.out.println(new BigDecimal(0.1d).add(new BigDecimal(0.1d)));  
  3.   
  4. System.out.println(new BigDecimal(0.2f));  
  5. System.out.println(new BigDecimal(0.1f).add(new BigDecimal(0.1f)));  
  6.   
  7. System.out.println(new BigDecimal(0.3d));  
  8. System.out.println(new BigDecimal(0.1d).add(new BigDecimal(0.1d)).add(new BigDecimal(0.1d)));  
  9.   
  10. System.out.println(new BigDecimal(0.3f));  
  11. System.out.println(new BigDecimal(0.1f).add(new BigDecimal(0.1f)).add(new BigDecimal(0.1
import tkinter def run1(): a = float(entry1.get()) b = float(entry2.get()) c = float(entry3.get()) d = a*b/c entry4.insert(tkinter.END,d) def run2(): file = open("实验记录.txt","w") data = float(entry1.get(),entry2.get(),entry3.get(),entry4.get()).split() file.write(data) file.close() root = tkinter.Tk() root.geometry ("320x240") root.title("氢氧化钠滴定醋酸浓度实验") label1 = tkinter.Label (root,text = "输入氢氧化钠浓度(mol/L):") label2 = tkinter.Label (root,text = "输入氢氧化钠体积(L):") label3 = tkinter.Label (root,text = "输入醋酸体积(L):") label4 = tkinter.Label (root,text = "醋酸的浓度是(mol/L):") label1 .place (relx=0.1,rely=0.1,relheight=0.15,relwidth=0.5) label2 .place (relx=0.1,rely=0.3,relheight=0.15,relwidth=0.4) label3 .place (relx=0.1,rely=0.5,relheight=0.15,relwidth=0.4) label4 .place (relx=0.1,rely=0.7,relheight=0.15,relwidth=0.4) entry1 = tkinter.Entry(root) entry2 = tkinter.Entry(root) entry3 = tkinter.Entry(root) entry4 = tkinter.Text(root) entry1.place(relx=0.6,rely=0.1,relheight=0.15,relwidth=0.3) entry2.place(relx=0.6,rely=0.3,relheight=0.15,relwidth=0.3) entry3.place(relx=0.6,rely=0.5,relheight=0.15,relwidth=0.3) entry4.place(relx=0.6,rely=0.7,relheight=0.15,relwidth=0.3) button1 = tkinter.Button (root,text="计算醋酸的浓度",command=run1) button2 = tkinter.Button (root,text="保存数据",command=run2) button1.place(relx=0.2,rely=0.89,relheight=0.1,relwidth=0.3) button2.place(relx=0.6,rely=0.89,relheight=0.1,relwidth=0.3) root.mainloop()检查错误
06-01
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值