亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > JS > 正文

JS浮點數運算結果不精確的Bug解決

2024-05-06 16:53:55
字體:
來源:轉載
供稿:網友

前言

最近在做項目的時候,涉及到產品價格的計算,經常會出現JS浮點數精度問題,這個問題,對于財務管理系統的開發者來說,是個非常嚴重的問題(涉及到錢相關的問題都是嚴重的問題),這里把相關的原因和問題的解決方案整理一下,也希望給各位提供一些參考。

一. 常見例子  

 // 加法 0.1 + 0.2 = 0.30000000000000004 0.1 + 0.7 = 0.7999999999999999 0.2 + 0.4 = 0.6000000000000001 // 減法 0.3 - 0.2 = 0.09999999999999998 1.5 - 1.2 = 0.30000000000000004 // 乘法 0.8 * 3 = 2.4000000000000004 19.9 * 100 = 1989.9999999999998 // 除法 0.3 / 0.1 = 2.9999999999999996 0.69 / 10 = 0.06899999999999999 // 比較 0.1 + 0.2 === 0.3 // false (0.3 - 0.2) === (0.2 - 0.1) // false

二. 導致原因

JavaScript 內部只有一種數字類型Number,也就是說,JavaScript 語言的底層根本沒有整數,所有數字都是以IEEE-754標準格式64位浮點數形式儲存,1與1.0是相同的。因為有些小數以二進制表示位數是無窮的。JavaScript會把超出53位之后的二進制舍棄,所以涉及小數的比較和運算要特別小心。

三. IEEE二進制浮點數算術標準(IEEE 754)

IEEE二進制浮點數算術標準(IEEE 754)是20世紀80年代以來最廣泛使用的浮點數運算標準,為許多CPU與浮點運算器所采用。這個標準定義了表示浮點數的格式(包括負零-0)與反常值(denormal number)),一些特殊數值(無窮(Inf)與非數值(NaN)),以及這些數值的“浮點數運算符”;它也指明了四種數值舍入規則和五種例外狀況(包括例外發生的時機與處理方式)。

四. 浮點數的存儲

JS的浮點數實現也是遵循IEEE 754標準,采用雙精度存儲(double precision),使用64位固定長度來表示,其中1位用來表示符號位,11位用來表示指數,52位表示尾數。如下圖:

JS,浮點數,Bug

  • ?符號位(sign):第1位是正負數符號位,0代表正數,1代表負數
  • 指數位(Exponent):中間11位存儲指數,用來表示次方數
  • 尾數位(mantissa):最后的52位是尾數,超出部分自動進一舍零

五. 浮點數的計算步驟(0.1+0.2)

【1】首先,十進制的0.1和0.2會轉換成二進制的,但是由于浮點數用二進制表示是無窮的

0.1——>0.0001 1001 1001 1001 ...(1001循環)
 0.2——>0.0011 0011 0011 0011 ...(0011循環)

【2】IEEE754標準的64位雙精度浮點數的小數部分最多支持53位二進制,多余的二進制數字被截斷,所以兩者相加之后的二進制之和是

0.0100110011001100110011001100110011001100110011001101

【3】將截斷之后的二進制數字再轉換為十進制,就成了0.30000000000000004,所以在計算時產生了誤差

六. 解決辦法

【1】引用類庫

  • Math.js 
  • decimal.js   
  • big.js

【2】思路一:在知道小數位個數的前提下,可以考慮通過將浮點數放大倍數到整型(最后再除以相應倍數),再進行運算操作,這樣就能得到正確的結果了  

0.1 + 0.2 ——> (0.1 * 10 + 0.2 * 10) / 10 // 0.3
0.8 * 3 ——> ( 0.8 * 100 * 3) / 100         //2.4

【3】自定義一個轉換和處理函數 

 // f代表需要計算的表達式,digit代表小數位數 Math.formatFloat = function (f, digit) {  // Math.pow(指數,冪指數)  var m = Math.pow(10, digit);  // Math.round() 四舍五入  return Math.round(f * m, 10) / m; } console.log(Math.formatFloat(0.3 * 8, 1)); // 2.4 console.log(Math.formatFloat(0.35 * 8, 2)); // 2.8

【4】加法函數  

 /**  ** 加法函數,用來得到精確的加法結果  ** 說明:javascript的加法結果會有誤差,在兩個浮點數相加的時候會比較明顯。這個函數返回較為精確的加法結果。  ** 調用:accAdd(arg1,arg2)  ** 返回值:arg1加上arg2的精確結果  **/ function accAdd(arg1, arg2) {  var r1, r2, m, c;  try {  r1 = arg1.toString().split(".")[1].length;  } catch (e) {  r1 = 0;  }  try {  r2 = arg2.toString().split(".")[1].length;  } catch (e) {  r2 = 0;  }  c = Math.abs(r1 - r2);  m = Math.pow(10, Math.max(r1, r2));  if (c > 0) {  var cm = Math.pow(10, c);  if (r1 > r2) {   arg1 = Number(arg1.toString().replace(".", ""));   arg2 = Number(arg2.toString().replace(".", "")) * cm;  } else {   arg1 = Number(arg1.toString().replace(".", "")) * cm;   arg2 = Number(arg2.toString().replace(".", ""));  }  } else {  arg1 = Number(arg1.toString().replace(".", ""));  arg2 = Number(arg2.toString().replace(".", ""));  }  return (arg1 + arg2) / m; } //給Number類型增加一個add方法,調用起來更加方便。 Number.prototype.add = function (arg) {  return accAdd(arg, this); };

【5】減法函數

 /**  ** 減法函數,用來得到精確的減法結果  ** 說明:javascript的減法結果會有誤差,在兩個浮點數相減的時候會比較明顯。這個函數返回較為精確的減法結果。  ** 調用:accSub(arg1,arg2)  ** 返回值:arg1加上arg2的精確結果  **/ function accSub(arg1, arg2) {  var r1, r2, m, n;  try {  r1 = arg1.toString().split(".")[1].length;  } catch (e) {  r1 = 0;  }  try {  r2 = arg2.toString().split(".")[1].length;  } catch (e) {  r2 = 0;  }  m = Math.pow(10, Math.max(r1, r2)); //last modify by deeka //動態控制精度長度  n = (r1 >= r2) ? r1 : r2;  return ((arg1 * m - arg2 * m) / m).toFixed(n); } // 給Number類型增加一個mul方法,調用起來更加方便。 Number.prototype.sub = function (arg) {  return accMul(arg, this); };

【6】乘法函數

 /**  ** 乘法函數,用來得到精確的乘法結果  ** 說明:javascript的乘法結果會有誤差,在兩個浮點數相乘的時候會比較明顯。這個函數返回較為精確的乘法結果。  ** 調用:accMul(arg1,arg2)  ** 返回值:arg1乘以 arg2的精確結果  **/ function accMul(arg1, arg2) {  var m = 0,  s1 = arg1.toString(),  s2 = arg2.toString();  try {  m += s1.split(".")[1].length;  } catch (e) {}  try {  m += s2.split(".")[1].length;  } catch (e) {}  return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m); } // 給Number類型增加一個mul方法,調用起來更加方便。 Number.prototype.mul = function (arg) {  return accMul(arg, this); };

【7】除法函數

  /**    ** 除法函數,用來得到精確的除法結果   ** 說明:javascript的除法結果會有誤差,在兩個浮點數相除的時候會比較明顯。這個函數返回較為精確的除法結果。   ** 調用:accDiv(arg1,arg2)   ** 返回值:arg1除以arg2的精確結果   **/  function accDiv(arg1, arg2) {   var t1 = 0,    t2 = 0,    r1, r2;   try {    t1 = arg1.toString().split(".")[1].length;   } catch (e) {}   try {    t2 = arg2.toString().split(".")[1].length;   } catch (e) {}   with(Math) {    r1 = Number(arg1.toString().replace(".", ""));    r2 = Number(arg2.toString().replace(".", ""));    return (r1 / r2) * pow(10, t2 - t1);   }  }  //給Number類型增加一個div方法,調用起來更加方便。  Number.prototype.div = function (arg) {   return accDiv(this, arg);  };

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對VeVb武林網的支持。


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
成人国产精品久久久久久亚洲| 亚洲国产小视频在线观看| 国产精品极品在线| 国产成人精品免费久久久久| 伊人久久大香线蕉av一区二区| 最新国产精品拍自在线播放| 欧美在线国产精品| 国产精品日日做人人爱| 亚洲激情小视频| 亚洲一区二区久久久久久| 亚洲成色www8888| 九九精品视频在线观看| 久久91精品国产91久久跳| 日韩成人在线视频观看| 欧美华人在线视频| 日韩电影免费观看在线观看| 91精品国产综合久久久久久久久| 中国日韩欧美久久久久久久久| 国产精品久久久久久一区二区| 欧美在线视频一区二区| 国产成人一区二区三区电影| 欧美激情视频网站| 国模吧一区二区三区| 精品自拍视频在线观看| 一区二区三区国产在线观看| 亚洲精品aⅴ中文字幕乱码| 国产精品自拍偷拍视频| 成人激情春色网| 国产精品99久久久久久白浆小说| 国产91对白在线播放| 日韩美女视频免费在线观看| 午夜精品一区二区三区在线播放| 日韩资源在线观看| 91精品啪aⅴ在线观看国产| 亚洲欧洲日产国码av系列天堂| 久久久欧美一区二区| 精品美女国产在线| 久久久亚洲国产天美传媒修理工| 亚洲免费人成在线视频观看| 在线播放精品一区二区三区| 成人中文字幕在线观看| 欧美整片在线观看| 亚洲成人教育av| 美女少妇精品视频| 精品日韩中文字幕| 国产情人节一区| 精品亚洲一区二区三区四区五区| 美女国内精品自产拍在线播放| 2025国产精品视频| 国产精品久久综合av爱欲tv| 国产精品久久久亚洲| 国产精品久久国产精品99gif| 亚洲性生活视频在线观看| 精品一区二区亚洲| 国产精品免费小视频| 国产精品揄拍一区二区| 亚洲国产精品va| 国产亚洲成av人片在线观看桃| 亚洲成人精品av| 日韩欧美在线观看视频| 91成人精品网站| 日韩欧美在线中文字幕| 欧美激情一区二区三区在线视频观看| 国产一区二区三区免费视频| 精品久久久久久久久久| 国产女精品视频网站免费| 欧美日韩中国免费专区在线看| 久久精品国产成人精品| 国产精品男人的天堂| 亚洲香蕉成人av网站在线观看| 国产日韩欧美日韩| 亚洲aⅴ日韩av电影在线观看| 亚洲第一网中文字幕| 亚洲丁香久久久| 夜色77av精品影院| 97在线观看视频国产| 欧亚精品中文字幕| 日韩精品日韩在线观看| 国产成人午夜视频网址| 91精品久久久久久| 亚洲色图激情小说| 免费不卡在线观看av| 日韩欧美一区二区在线| 国产精品99蜜臀久久不卡二区| 国产精品美女久久久久久免费| 亚洲成人免费网站| 精品女同一区二区三区在线播放| 亚洲男女性事视频| 欧美激情精品久久久久久黑人| 亚洲福利小视频| 国产精品18久久久久久麻辣| 欧美精品久久久久| 亚洲直播在线一区| 最近2019免费中文字幕视频三| 欧美乱人伦中文字幕在线| 国产精品成久久久久三级| 黄色精品一区二区| 国产精品高潮呻吟视频| 欧美性猛交xxxx乱大交极品| 一区二区三区在线播放欧美| 成人网址在线观看| 免费av一区二区| 久久噜噜噜精品国产亚洲综合| 韩曰欧美视频免费观看| 狠狠色香婷婷久久亚洲精品| 欧美激情一级欧美精品| 永久免费毛片在线播放不卡| 狠狠久久五月精品中文字幕| 欧美视频精品一区| 亚洲白拍色综合图区| 久久中文字幕国产| 国内精品久久久久久久久| 最新日韩中文字幕| 亚洲欧美日韩在线一区| 久久久久久久久久久av| 日韩视频免费大全中文字幕| 另类天堂视频在线观看| 精品成人乱色一区二区| 2019中文字幕免费视频| 久久久久亚洲精品国产| 最近2019中文字幕第三页视频| 色婷婷av一区二区三区久久| 日韩精品在线免费播放| 国产小视频国产精品| 欧美日本国产在线| 日本一区二区不卡| 久久久久久久久久婷婷| 成年人精品视频| 羞羞色国产精品| 亚洲最大av网站| 国产999精品| 久久九九免费视频| 久久免费在线观看| 国产精品视频专区| 欧美插天视频在线播放| 国产69精品99久久久久久宅男| 在线观看视频亚洲| …久久精品99久久香蕉国产| 色综合亚洲精品激情狠狠| 国产精品视频导航| 美日韩精品免费观看视频| 欧洲日本亚洲国产区| 热久久这里只有| 久久99国产精品自在自在app| 欧美疯狂性受xxxxx另类| 亚洲国产精品成人va在线观看| 一本色道久久88综合日韩精品| 欧美最猛性xxxxx亚洲精品| 欧美日韩在线视频一区二区| 欧美区二区三区| 亚洲人成五月天| 国产亚洲a∨片在线观看| 精品中文字幕在线2019| 亚洲欧美一区二区精品久久久| 2023亚洲男人天堂| 精品福利在线观看| 欧美日韩黄色大片| 在线日韩av观看| 国产一区二区在线免费| 国内精品400部情侣激情| 2019国产精品自在线拍国产不卡| 欧美成人性色生活仑片| 成人a视频在线观看| 日韩在线观看免费高清完整版|