JS浮点数BUG

JavaScript 2017-03-21 JavaScript,浮点数,IEEE754

之前就有看过JS浮点数BUG的相关文章,但没有特别关注,直到最近做一个项目,正好是涉及到浮点运算,看了好几次确认逻辑没有问题以后断点跟踪发现了传说中的浮点数BUG.

$ node
> 0.8 - 0.1
0.7000000000000001

这跟运行环境还没有关系,比如浏览器下

但不是每个浮点书运算都会有这个bug,比如:

$ node
> 0.8 - 0.1
0.7000000000000001
> 0.9 - 0.8
0.09999999999999998
> 1.0 - 0.1
0.9
> 1.0 - 0.4
0.6
> 0.4 - 0.3
0.10000000000000003
> 0.1 + 0 。1
0.1 + 0 。1
        ^
SyntaxError: Invalid or unexpected token

> 0.1 + 0.1
0.2
> 0.5 + 0.1
0.6
>

再来一个

> 0.1 * 0.1
0.010000000000000002
> 0.5 / 0.3
1.6666666666666667
> 0.9 / 0.3
3

据说是因为JS采用了IEEE754 FP编码的,那问题就来了,采用 IEEE754 FP 编码的语言也不仅只有JS啊,看看维基百科

IEEE二进制浮点数算术标准IEEE 754)是20世纪80年代以来最广泛使用的浮点数运算标准,为许多CPU浮点运算器所采用。这个标准定义了表示浮点数的格式(包括负零-0)与反常值(denormal number)),一些特殊数值(无穷(Inf)与非数值(NaN)),以及这些数值的“浮点数运算符”;它也指明了四种数值舍入规则和五种例外状况(包括例外发生的时机与处理方式)。

IEEE 754规定了四种表示浮点数值的方式:单精确度(32位)、双精确度(64位)、延伸单精确度(43比特以上,很少使用)与延伸双精确度(79比特以上,通常以80位实现)。只有32位模式有强制要求,其他都是选择性的。大部分编程语言都有提供IEEE浮点数格式与算术,但有些将其列为非必需的。例如,IEEE 754问世之前就有的C语言,现在有包括IEEE算术,但不算作强制要求(C语言的float通常是指IEEE单精确度,而double是指双精确度)。

该标准的全称为IEEE二进制浮点数算术标准(ANSI/IEEE Std 754-1985),又称IEC 60559:1989,微处理器系统的二进制浮点数算术(本来的编号是IEC 559:1989)[1]。后来还有“与基数无关的浮点数”的“IEEE 854-1987标准”,有规定基数为2跟10的状况。现在最新标准是“ISO/IEC/IEEE FDIS 60559:2010”。

在六、七十年代,各家计算机公司的各个型号的计算机,有着千差万别的浮点数表示,却没有一个业界通用的标准。这给数据交换、计算机协同工作造成了极大不便。IEEE的浮点数专业小组于七十年代末期开始酝酿浮点数的标准。在1980年,英特尔公司就推出了单片的8087浮点数协处理器,其浮点数表示法及定义的运算具有足够的合理性、先进性,被IEEE采用作为浮点数的标准,于1985年发布。而在此前,这一标准的内容已在八十年代初期被各计算机公司广泛采用,成了事实上的业界工业标准。加州大学伯克利分校的数值计算与计算机科学教授威廉·卡韩被誉为“浮点数之父”。

可见C语言也采用了,但C语言又有相应的类库来解决了这个BUG,JS没有,于是网上就出现大量的关于JS浮点运算BUG的解决方法,其实很简单,既然浮点运算有BUG,那我们可以先转成整形运算后再转回浮点即可

> (0.8 * 10 - 0.1 * 10) / 10
0.7
> 0.8 - 0.1
0.7000000000000001
> 0.1 * (0.1 * 10) / 10
0.01
> 0.1 * 0.1
0.010000000000000002

于是大家更愿意封装成函数,来解决理浮点型运算的问题,当然,密集型运算还是不要上JS了

文字链接:《JS浮点数BUG

文章地址:http://www.qttc.net/201703482.html

除非标注,琼台博客所有博文均为原创,转载请加文字链接注明来源

乳名?小名?昵称?网名?均可

email,放心,我不会给你乱投广告的

想获得回访就把你的站点URL写上(没有留空)

[NOTICE]木要投放广告
[NOTICE]木要骂人,说不该说的话
[NOTICE]自由言论,但要遵纪守法

Comments 3