JS运算精度问题讨论

202 阅读3分钟
  • JS采用IEEE754标准。

  • 64位双精度。

  • 因为计算机内部以2进制存储数据,不是以二进制存储数据,当进行小数运算时,二进制表示法可能会出现无限循环,所以小数运算的结果就再转换为十进制就只能是一个近似结果。

  • javascript以64位双精度浮点数存储所有Number类型值 即计算机最多存储64位二进制数。

  • 对二进制的浮点数采用科学计数法来固定小数点位置。

  • 计算机存储二进制即为:符号位+指数位+小数部分 (阶数)。

  • 双精度浮点数的指数偏移量都为1023。

  • 计算机存储一个27.5的数字

    • 首先把这个数字转换为二进制 11011.1
    • 再把二进制转换为科学记数法 [公式]
    • 又因js存储数字用的是双精度浮点数【最多存储64位】 即 符号位【1】+指数位【4+1023(固定偏移量)=> 10000000011】+小数部分【10111(52位不够用0补齐)】
    • 即 0100 0000 0011 1011 1000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
  • 在转换为二进制的科学记数法的形式时只保留64位有效的数字,此时只能模仿十进制进行四舍五入了,但是二进制只有 0 和 1 两个,于是变为 0 舍 1 入。在这一步出现了错误,那么一步错步步错,那么在计算机存储小数时也就理所应当的出现了误差。这即是计算机中部分浮点数运算时出现误差,这就是丢失精度的根本原因**。**

  • 计算机存储双精度浮点数需要先把十进制数转换为二进制的科学记数法的形式,然后计算机以自己的规则{符号位+(指数位+指数偏移量的二进制)+小数部分}存储二进制的科学记数法,因为存储时有位数限制(64位),并且某些十进制的浮点数在转换为二进制数时会出现无限循环,会造成二进制的舍入操作(0舍1入),当再转换为十进制时就造成了计算误差。

  • 为什么0.1赋值能得到0.1:js自己做了精度处理,保留16位有效位数。

  • 大数危机:最多16位有效位,不丢精度最多能表示的大数为2的53次方——9007199254740992,大于这个的数就有可能出现精度丢失问题。

  • 使用parseInt()时也会有这种问题 parseInt()把字符串转换为整数后存储机制和浮点数是一样的,当大于 9007199254740992 的可能会丢失精度。

  • 怎么理解能最大 表示的整数是2的53次方:

  • 解决方案: