JavaScript的高精度計算與JSON.parse的BIGINT

在JavaScript處理整數的時候會遇到某些特別奇怪的問題,好比後臺給你返回了一個超長的數字,而後js在計算的時候忽然發現計算不對,不是後面爲0就是計算得不到想要的結果.這裏涉及到一個很簡單的知識 也就是NUMBER的安全整數.node

Number安全整數

Number.MAX_SAFE_INTEGER // 9007199254740991
9007199254740991+2 // 9007199254740992

複製代碼

首先咱們拿到了安全範圍內的數字 而後對他進行簡單的加法,正常的結果應該是9007199254740993 可是這裏的尾數只有2, 你們能夠去測試一下也是挺有意思的。由於js中全部的整數都是用浮點類型(double-precision 64-bit binary format IEEE 754 value)致使的,雖然能夠承受的範圍比較大,可是計算精度卻不怎麼好git

計算精度

說完了安全整數這裏來簡單說說計算精度github

0.1+0.2 //0.30000000000000004
複製代碼

原理也是同上 那麼解決辦法也很簡單ajax

使用math.js庫便可解決json

// prevent round-off errors showing up in output
var ans = math.add(0.1, 0.2);       //  0.30000000000000004
math.format(ans, {precision: 14});  // '0.3'
複製代碼

JSON.parse中遇到的BIGINT

比較常見的場景爲後臺返回了一串JSON可是數字爲BIGINT致使解析錯誤,通常爲16位安全

var c='{"num": 90071992547409999}'
JSON.parse(c) // {num: 90071992547410000}
複製代碼

好比咱們使用jQuery的ajax開啓了json:true功能 jQuery會自動parse 這樣的話會形成精度不夠的問題,因此這裏能夠使用json-bigintbash

var JSONbig = require('json-bigint');

var json = '{ "value" : 9223372036854775807, "v2": 123 }';
console.log('Input:', json);
console.log('');

console.log('node.js bult-in JSON:')
var r = JSON.parse(json);
console.log('JSON.parse(input).value : ', r.value.toString());
console.log('JSON.stringify(JSON.parse(input)):', JSON.stringify(r));

console.log('\n\nbig number JSON:');
var r1 = JSONbig.parse(json);
console.log('JSON.parse(input).value : ', r1.value.toString());
console.log('JSON.stringify(JSON.parse(input)):', JSONbig.stringify(r1));

// output

Input: { "value" : 9223372036854775807, "v2": 123 }

node.js bult-in JSON:
JSON.parse(input).value :  9223372036854776000
JSON.stringify(JSON.parse(input)): {"value":9223372036854776000,"v2":123}


big number JSON:
JSON.parse(input).value :  9223372036854775807
JSON.stringify(JSON.parse(input)): {"value":9223372036854775807,"v2":123}
複製代碼

若是不想要引入額外的庫則能夠參考這段函數函數

let stringedJSON = origJSON.replace(/:\s*([-+Ee0-9.]+)/g, ': "uniqueprefix$1"');

let o = JSON.parse(stringedJSON, (key, value) => {
  // only changing strings
  if (typeof value !== 'string') return value;
  // only changing number strings
  if (!value.startsWith('uniqueprefix')) return value;
  // chop off the prefix
  value = value.slice('uniqueprefix'.length);
  // pick your favorite arbitrary-precision library
  return new Big(value);
});
複製代碼

參考文獻測試

相關文章
相關標籤/搜索