JS中如何理解浮点数? (2)

上图中,对所得的和,“零舍一入”保留 52 位有效小数就是最终的值:0.01001100...110100(第 53 位是 1 ,所以往前进了 1),如下代码所示。这个值与上文中的 0.3 的最终二进制表示的值明显不相同,即解释了 0.1 + 0.2 不等于 0.3 的根本原因所在(实际上,这个值转化为 10 进制约等于 0.30000000000000004)。注:打印出来的长度是 54,因为有 52 位有效小数,前面是'0.01',长度是 4,最后去掉末尾的 2 个 0,所以最后打印出来的长度是 52+4-2 = 54。

var d = 0.1 + 0.2;console.log(d.toString(2)); //0.0100110011001100110011001100110011001100110011001101console.log(d.toString(2).length); // 54 浮点数精度运算解决方案

关于 js 浮点数运算精度丢失的问题,不同场景可以有不同的解决方案。 1、如果只是用来展示一个浮点数的结果,则可以借用 Number 对象的 toFixed 和 parseFloat 方法。下面代码片段中,fixed 参数表示要保留几位小数,可以根据实际场景调整精度。

function formatNum(num, fixed = 10) { return parseFloat(a.toFixed(fixed))}var a = 0.1 + 0.2;console.log(formatNum(a)); //0.3

2、如果需要进行浮点数的加减乘除等运算,由上文可知,在小于 Number.MAXSAFEINTEGER 范围的整数是可以被精确表示出来的,所以可以先把小数转化为整数,运算得到结果后再转化为对应的小数。比如两个浮点数的加法:

function add(num1, num2) { var decimalLen1 = (num1.toString().split('.')[1] || '').length; //第一个参数的小数个数 var decimalLen2 = (num2.toString().split('.')[1] || '').length; //第二个参数的小数个数 var baseNum = Math.pow(10, Math.max(decimalLen1, decimalLen2)); return (num1 * baseNum + num2 * baseNum) / baseNum;}console.log(add(0.1 , 0.2)); //0.3

参考资料

https://en.wikipedia.org/wiki/IEEE_754

https://en.wikipedia.org/wiki/Double-precision_floating-point_format

https://en.wikipedia.org/wiki/Normal_number_(computing)

https://en.wikipedia.org/wiki/Denormal_number

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpzgzj.html