关于浮点数0.57 0.58 造出的坑爹问题

来源:互联网 发布:动易cms价格 编辑:程序博客网 时间:2024/05/19 09:09

转自:http://justjavac.iteye.com/blog/1864938


今天看到 vb2005xu 提到了一个问题  浮点数0.57 0.58 造出的坑爹问题。 

parseInt(0.59*100)  // 59parseInt(0.58*100)  // 57parseInt(0.57*100)  // 56parseInt(0.56*100)  // 56

 为什么会这样呢?随后又举了 PHP 的例子,结果还是一样的结果,只是函数换成了 intval,于是 vb2005xu 猜想,是不是 python 也这样呢。 
这个问题看似奇特,其实还是浮点数的精度的问题,我以前写的这篇文章:代码之谜(五)- 浮点数(谁偷了你的精度?) 
0.58*100 的结果是什么?其实大家试试就知道了,并不是想象中的 58,而是 57.99999999999999。为什么?看我上面的文章。 
是 js 或者 php 这些动态语言的怪癖吗?C语言,java会这样吗? 
其实 0.58*100 = 57.99999999999999 是不局限于任何语言的,是 IEEE 规定的浮点数的运算标准。一般情况下,57.99999999999999 会四舍五入到 58。需要注意的是,浮点数的四舍五入和咱们普通的数学里面的也是不同的,浮点数遇到 5 后,不一定总是入,有时也舍,具体细节不多解释了。
为什么结果是 57 呢,主要是因为 parseInt 和 intval 函数。他们的规则是,从第一个数字开始,知道遇到不是数字的字符,结束。
所以 
parseInt("012") 结果是 10 (不要惊讶,0开头的数字是八进制)
parseInt("12abc") 结果是 12 (不解释)
parseInt("12.123") 结果是 12
12e5 是多少呢?科学计数法,结果是 1200000(12后面五个0)
parseInt("12e5") 的结果呢?结果是12,因为e字符不是数字,所以后面的都忽略了。
parseInt("abc") 这个呢?结果是0?如果是0的话,你让 parseInt("0abc") 情何以堪啊!结果是 NaN (Not a Number)。 
-----------------2013-05-09 17:12 补充-----------------------------------------
vb2005xu 写道
此处的精度问题 为什么 只有0.57/0.58 这两个有问题 而 0.59 0.56 等却没有问题呢
 由于时间问题,临近下班了,所以不细解释了。还是这篇文章,代码之谜(五)- 浮点数(谁偷了你的精度?),仔细品味一下。如果把它们写出2进制浮点数,就明白了。其实一个令人震惊的事实就是,99%的数不能够被精确的表示为浮点数。

0.56*10056.000000000000010.57*10056.999999999999990.58*10057.999999999999990.59*10059
看到上面的表格,好像 0.59 可以精确表示一样,其实不然,首先,0.59的末尾是9,意味着他不可能被转换成有限二进制小数(why?)。肯定是一个循环小数,如果循环节超过了浮点数的尾数,那么就给人一种可以精确表示的假象。(设计到很多公式,就不写了,以后专门写博客讨论)。

运行: 0.59*1e71
结果: 5.9e+70

运行: 0.59*1e72
结果: 5.899999999999999e+71

看出端倪来了吗?
原创粉丝点击