诡异的数值精度丢失

问题描述

在一次开发列表编辑页面时发现一个诡异的问题,列表展现的数据和回显的数据不同,第一反应是接口出错了,查看了一下ajax请求,好像确实是这样:ajax

列表请求接口: npm

列表查询请求

数据回显请求接口:浏览器

数据回显请求
数据回显请求

很明显列表数据和回显数据不一致,因而就找服务端同窗排查接口问题。服务端同窗反馈从日志上看是没问题的,对比他们日志,发现日志打印的数据和界面展现的不一致,诡异的事情就这样发生了。更诡异的是直接在浏览器地址栏访问这个接口,返回的数据和日志的同样,和我界面展现的也不一致。bash

地址栏请求数据

看样子应该是我项目中请求对数据作了处理,回过头再来看请求的数据,对比发现 driverId 数值,初步定为是由于数值类型精度丢失。spa

let num = 1001379549335920640
// 1001379549335920600
复制代码

精度丢失缘由

js数值类型遵循IEEE 754规范,占用64位,日志

s eeeeeee eeee ffff ffffffff ffffffff  ffffffff ffffffff ffffffff ffffffff
复制代码

从左起code

  • 1位用来表示符号
  • 11位用来表示指数
  • 52表示尾数

这种表示方法直接致使了精度丢失,当数值没法用二进制表示时,就会采起0舍1入。cdn

浮点数和大整数都会出现精度丢失。当大整数尾数大于 2^52 = 9007199254740992 时就可能精度丢失blog

9007199254740992     >> 10000000000000...000 // 共计 53 个 0
9007199254740992 + 1 >> 10000000000000...001 // 中间 52 个 0
9007199254740992 + 2 >> 10000000000000...010 // 中间 51 个 0
复制代码
9007199254740992 + 1 // 丢失
// 9007199254740992 
9007199254740992 + 2 // 未丢失
// 9007199254740994
9007199254740992 + 3 // 丢失
// 9007199254740996
9007199254740992 + 4 // 未丢失
// 9007199254740996
复制代码

解决方案

  • 若是数值自己不参与运算,能够换成字符类型
  • 若是数值在常规范围内,能够先把小数放大到整数,运算后在缩小原来整数倍
// 0.1 + 0.2
(0.1*10 + 0.2*10) / 10 == 0.3 // true
复制代码
  • 若是对精度有严格要求,能够本身实现大数运算,或借助npm包(例如big.js
相关文章
相关标签/搜索