浮点数运算的误差
浮点数运算的误差
在 javascript 中整数和浮点数都属于number 数据类型,所有数字都是使用64位浮点数形式储存,遵循ieee-754双精度标准存储,即便整数也是如此。 所以我们在打印 1.00 这样的浮点数的结果是 1 而非 1.00。而有时候用浮点数进行数学运算的时候,发现居然会有一些误差,比如:
<script type="text/javascript"> console.log("加法:"); console.log("0.1 + 0.2 = " + (0.1 + 0.2)); console.log("0.7 + 0.1 = " + (0.7 + 0.1)); console.log("0.2 + 0.4 = " + (0.2 + 0.4)); console.log("减法:"); console.log("0.3 - 0.2 = " + (0.3 - 0.2)); console.log("乘法:"); console.log("19.9 * 100 = " + (19.9 * 100)); console.log("9.7 * 100 = " + (9.7 * 100)); console.log("除法:"); console.log("0.3 / 0.1 = " + (0.3 / 0.1)); console.log("0.69 / 10 = " + (0.69 / 10)); </script>
结果为:
那么原因在哪呢??
javascript 里的数字是采用 ieee 754 标准 的 64 位双精度浮点数。该规范定义了浮点数的格式,对于64位的浮点数在内存中的表示,最高的1位是符号位,接着的11位是指数,剩下的52位为有效数字,具体:
其中:
- 符号位 s(sign)决定数是正数(s=0)还是负数(s=1),而对于数值 0 的符号位解释则作为特殊情况处理。
- 有效数字位 m(significand)是二进制小数,它的取值范围为 1~2-ε,或者为 0~1-ε。它也被称为尾数位(mantissa)、系数位(coefficient),甚至还被称作“小数”
- 指数位 e(exponent)是 2 的幂(可能是负数),它的作用是对浮点数加权。
符号位决定了一个数的正负,指数部分决定了数值的大小,小数部分决定了数值的精度。 ieee 754规定,有效数字第一位默认总是1,不保存在64位浮点数之中。也就是说,有效数字总是1.xx…xx的形式,其中xx..xx的部分保存在64位浮点数之中,最长可能为52位。因此,javascript提供的有效数字最长为53个二进制位(64位浮点的后52位+有效数字第一位的1)。
那么举个例子:
计算 0.1 + 0.2 时,内存中发生的事:
首先,十进制的 0.1 和 0.2 都会被转换成二进制,但由于浮点数用二进制表达时是无穷的,即
- 0.1 -> 0.0001100110011001...(无限)
- 0.2 -> 0.0011001100110011...(无限)
ieee 754 标准的 64 位双精度浮点数的小数部分最多支持 53 位二进制位,所以两者相加之后得到二进制为:
- 0.0100110011001100110011001100110011001100110011001100
因浮点数小数位的限制而截断的二进制数字,再转换为十进制,就成了 0.30000000000000004。所以在进行算术计算时会产生误差。
那么怎么解决这个误差呢?
一般使用 tofixed() 方法 ,语法为:
数值.tofixed(num);
num 是精确的位数,例如:
var num = 13.14520; console.log(num.tofixed(2));
结果为: 13.14
上一篇: 北京秋分吃啥?北京秋分饮食文化
下一篇: 时区缩写