Skip to content

JS之Number类型精度丢失问题

问题: [雪花(snowflake)算法]生成的id如果用long类型返回前端(例如4858024458742925186),精度会丢失。

x|200

Number精度是16位,超过会造成精度丢失。
目前解决方法是后端转成字符串返回处理。 并注意前端不要转换数字类型。 例如 +(Number)等。

说明

响应体中的长整型显示错误 · Issue #135 · xiaoymin/swagger-bootstrap-ui

js处理long型丢失精度问题 | Hzzly

JavaScript 内部只有一种数字类型 Number,所有数字都是采用 IEEE 754 标准定义的双精度 64 位格式存储,即使整数也是如此。这就是说,JavaScript 语言的底层根本没有整数,所有数字都是小数(64 位浮点数)。其结构如图:

各位的含义如下:

  • 1 位(s) 用来表示符号位,0 表示正数,1 表示负数
  • 11 位(e) 用来表示指数部分
  • 52 位(f) 表示小数部分(即有效数字)

双精度浮点数(double)并不是能够精确表示范围内的所有数, 虽然双精度浮点型的范围看上去很大: 。 可以表示的最大整数可以很大,但能够精确表示,使用算数运算的并没有这么大。因为小数部分最大是 52 位,因此 JavaScript 中能精准表示的最大整数是 ,十进制即 9007199254740991

js
console.log(Math.pow(2, 53) - 1);  
console.log(1L<<53);  
9007199254740991
console.log(Math.pow(2, 53) - 1);  
console.log(1L<<53);  
9007199254740991

JavaScript 有所谓的最大和最小安全值:

js
console.log(Number.MAX_SAFE_INTEGER);  
console.log(Number.MIN_SAFE_INTEGER);  
9007199254740991 - 9007199254740991;
console.log(Number.MAX_SAFE_INTEGER);  
console.log(Number.MIN_SAFE_INTEGER);  
9007199254740991 - 9007199254740991;

josdejong/lossless-json: Parse JSON without risk of losing numeric information

js
import { parse, stringify, isSafeNumber, isInteger } from 'lossless-json';


const str = '{"id":1234567890123456789,"id2":12345, "name":"收到"}';  
// 精度丢失
const x = JSON.parse(str).id;  
console.log('content:', x); // 1234567890123456800    
const json = parse(str); // {foo: 'bar'}  
// 精度没有丢失
console.log('json:', json);

/*  
json: {id: e}  
id: e {isLosslessNumber: true, value: '1234567890123456789'}  
[[Prototype]]: Object  
 */// 测试解析common  
const xxxxx = parse(str, undefined, (value) => {  
  console.log('isSafeNumber', value, isSafeNumber(value));  
  if (isSafeNumber(value)) {  
    return +value;  
  }  
  return value.toString();  
});  
console.log(xxxxx);
import { parse, stringify, isSafeNumber, isInteger } from 'lossless-json';


const str = '{"id":1234567890123456789,"id2":12345, "name":"收到"}';  
// 精度丢失
const x = JSON.parse(str).id;  
console.log('content:', x); // 1234567890123456800    
const json = parse(str); // {foo: 'bar'}  
// 精度没有丢失
console.log('json:', json);

/*  
json: {id: e}  
id: e {isLosslessNumber: true, value: '1234567890123456789'}  
[[Prototype]]: Object  
 */// 测试解析common  
const xxxxx = parse(str, undefined, (value) => {  
  console.log('isSafeNumber', value, isSafeNumber(value));  
  if (isSafeNumber(value)) {  
    return +value;  
  }  
  return value.toString();  
});  
console.log(xxxxx);