商家创建一个发礼品券的活动,券金额0.1, 库存9999,那么活动成本是:0.1 × 9999 = 999.9000000000001
额。。。 不应该是99.99么??
原来计算机进行四则运算时,在某些情况下会有误差,这是在safari上的测试结果。
0.1 + 0.2 = 0.30000000000000004
1.0 - 0.8 = 0.19999999999999996
1.6 × 9999 = 15998.400000000001
999.9 ÷ 9999 = 0.09999999999999999
误差原因
要弄明白出现这种问题的原因,得知道计算机是怎么处理小数的。计算机处理的是二进制数据,只有0和1。将十进制整数转换成二进制很简单,商除以2取余,小数点左侧从右向左排列就是整数部分二进制了。将小数部分转换成二进制,小数部分乘以2取整,小数点右侧从左向右排列就是小数部分的二进制,就可能出现无限循环。例如:
十进制 6.1
二进制 110.0001 1001 1001 1001 …
整数部分 6 ,余数在小数点左侧的顺序 110.
6 ÷ 2 = 3 … 0
3 ÷ 2 = 1 … 1
1 ÷ 2 = 0 … 1
小数部分 0.1 , 取结果的整数部分,结果的小数部分继续乘以2,知道结果没有小数部分为止
在小数点右侧的顺序 .0001 1001 1001 …
0.1 × 2 = 0.2 0.2 + 0
0.2 × 2 = 0.4 0.4 + 0
0.4 × 2 = 0.8 0.8 + 0
0.8 × 2 = 1.6 0.6 + 1
0.6 × 2 = 1.2 0.2 + 1
0.2 × 2 = 0.4 0.4 + 0
0.4 × 2 = 0.8 0.8 + 0
0.8 × 2 = 1.6 0.6 + 1
0.6 × 2 = 1.2 0.2 + 1
0.2 × 2 = 0.4 0.4 + 0
0.4 × 2 = 0.8 0.8 + 0
0.8 × 2 = 1.6 0.6 + 1
…
说明,有些十进制小数是不能用二进制有限位数表示的。
十进制 | 二进制 |
---|---|
0.1 | 0.0001 1001 1001 1001 … |
0.2 | 0.0011 0011 0011 0011 … |
0.3 | 0.0100 1100 1100 1100 … |
0.4 | 0.0110 0110 0110 0110 … |
0.5 | 0.1 |
0.6 | 0.1001 1001 1001 1001 … |
计算机无法表示无限小数,会进行取舍,从而造成误差。
解决办法
对于加减法和乘法,可以先将参加运算的小数扩大n倍,变成整数,整数运算后再缩小n倍。对于除法,可以两个参数同时扩大n倍,再运算。例如加法运算: