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

首頁 > 編程 > JavaScript > 正文

詳解JavaScript 浮點數運算的精度問題

2019-11-19 11:09:06
字體:
來源:轉載
供稿:網友

問題描述

在 JavaScript 中整數和浮點數都屬于 Number 數據類型,所有數字都是以 64 位浮點數形式儲存,即便整數也是如此。 所以我們在打印 1.00 這樣的浮點數的結果是 1 而非 1.00 。在一些特殊的數值表示中,例如金額,這樣看上去有點變扭,但是至少值是正確了。然而要命的是,當浮點數做數學運算的時候,你經常會發現一些問題,舉幾個例子:

// 加法 =====================// 0.1 + 0.2 = 0.30000000000000004// 0.7 + 0.1 = 0.7999999999999999// 0.2 + 0.4 = 0.6000000000000001// 2.22 + 0.1 = 2.3200000000000003 // 減法 =====================// 1.5 - 1.2 = 0.30000000000000004// 0.3 - 0.2 = 0.09999999999999998 // 乘法 =====================// 19.9 * 100 = 1989.9999999999998// 19.9 * 10 * 10 = 1990// 1306377.64 * 100 = 130637763.99999999// 1306377.64 * 10 * 10 = 130637763.99999999// 0.7 * 180 = 125.99999999999999// 9.7 * 100 = 969.9999999999999// 39.7 * 100 = 3970.0000000000005 // 除法 =====================// 0.3 / 0.1 = 2.9999999999999996// 0.69 / 10 = 0.06899999999999999

問題的原因

似乎是不可思議。小學生都會算的題目,JavaScript 不會?我們來看看其真正的原因。

JavaScript 里的數字是采用 IEEE 754 標準的 64 位雙精度浮點數。該規范定義了浮點數的格式,對于64位的浮點數在內存中的表示,最高的1位是符號位,接著的11位是指數,剩下的52位為有效數字,具體:

  1. 第0位:符號位, s 表示 ,0表示正數,1表示負數;
  2. 第1位到第11位:儲存指數部分, e 表示 ;
  3. 第12位到第63位:儲存小數部分(即有效數字),f 表示,

如圖:

符號位決定了一個數的正負,指數部分決定了數值的大小,小數部分決定了數值的精度。 IEEE 754規定,有效數字第一位默認總是1,不保存在64位浮點數之中。也就是說,有效數字總是1.xx…xx的形式,其中xx..xx的部分保存在64位浮點數之中,最長可能為52位。因此,JavaScript提供的有效數字最長為53個二進制位(64位浮點的后52位+有效數字第一位的1)。

計算過程

比如在 JavaScript 中計算 0.1 + 0.2時,到底發生了什么呢?

首先,十進制的0.1和0.2都會被轉換成二進制,但由于浮點數用二進制表達時是無窮的,例如。

0.1 -> 0.0001100110011001...(無限)0.2 -> 0.0011001100110011...(無限)

IEEE 754 標準的 64 位雙精度浮點數的小數部分最多支持 53 位二進制位,所以兩者相加之后得到二進制為:

0.0100110011001100110011001100110011001100110011001100 

因浮點數小數位的限制而截斷的二進制數字,再轉換為十進制,就成了 0.30000000000000004。所以在進行算術計算時會產生誤差。

整數的精度問題

在 Javascript 中,整數精度同樣存在問題,先來看看問題:

console.log(19571992547450991); //=> 19571992547450990console.log(19571992547450991===19571992547450992); //=> true

同樣的原因,在 JavaScript 中 Number類型統一按浮點數處理,整數是按最大54位來算最大(253 - 1,Number.MAX_SAFE_INTEGER,9007199254740991) 和最小(-(253 - 1),Number.MIN_SAFE_INTEGER,-9007199254740991) 安全整數范圍的。所以只要超過這個范圍,就會存在被舍去的精度問題。

當然這個問題并不只是在 Javascript 中才會出現,幾乎所有的編程語言都采用了 IEEE-745 浮點數表示法,任何使用二進制浮點數的編程語言都會有這個問題,只不過在很多其他語言中已經封裝好了方法來避免精度的問題,而 JavaScript 是一門弱類型的語言,從設計思想上就沒有對浮點數有個嚴格的數據類型,所以精度誤差的問題就顯得格外突出。

解決方案

上面說了這么多問題和原因,這里給出一些解決方案。

類庫

通常這種對精度要求高的計算都應該交給后端去計算和存儲,因為后端有成熟的庫來解決這種計算問題。前端也有幾個不錯的類庫:

Math.js

Math.js 是專門為 JavaScript 和 Node.js 提供的一個廣泛的數學庫。它具有靈活的表達式解析器,支持符號計算,配有大量內置函數和常量,并提供集成解決方案來處理不同的數據類型

像數字,大數字(超出安全數的數字),復數,分數,單位和矩陣。 功能強大,易于使用。

官網:http://mathjs.org/

GitHub:https://github.com/josdejong/mathjs

decimal.js

為 JavaScript 提供十進制類型的任意精度數值。

官網:http://mikemcl.github.io/decimal.js/

GitHub:https://github.com/MikeMcl/decimal.js

big.js

官網:http://mikemcl.github.io/big.js

GitHub:https://github.com/MikeMcl/big.js/

這幾個類庫幫我們解決很多這類問題,不過通常我們前端做這類運算通常只用于表現層,應用并不是很多。所以很多時候,一個函數能解決的問題不需要引用一個類庫來解決。

下面介紹各個更加簡單的解決方案。

整數表示

對于整數,我們可以通過用String類型的表示來取值或傳值,否則會喪失精度。

格式化數字、金額、保留幾位小數等

如果只是格式化數字、金額、保留幾位小數等可以查看這里 http://www.49028c.com/article/165993.htm

浮點數運算

toFixed() 方法

浮點數運算的解決方案有很多,這里給出一種目前常用的解決方案, 在判斷浮點數運算結果前對計算結果進行精度縮小,因為在精度縮小的過程總會自動四舍五入。

toFixed() 方法使用定點表示法來格式化一個數,會對結果進行四舍五入。語法為:

numObj.toFixed(digits)

參數 digits 表示小數點后數字的個數;介于 0 到 20 (包括)之間,實現環境可能支持更大范圍。如果忽略該參數,則默認為 0。

返回一個數值的字符串表現形式,不使用指數記數法,而是在小數點后有 digits 位數字。該數值在必要時進行四舍五入,另外在必要時會用 0 來填充小數部分,以便小數部分有指定的位數。 如果數值大于 1e+21,該方法會簡單調用 Number.prototype.toString()并返回一個指數記數法格式的字符串。

特別注意:toFixed() 返回一個數值的字符串表現形式。

具體可以查看MDN中的說明,那么我們可以這樣解決精度問題:

parseFloat((數學表達式).toFixed(digits)); // toFixed() 精度參數須在 0 與20 之間// 運行parseFloat((1.0 - 0.9).toFixed(10)) // 結果為 0.1 parseFloat((0.3 / 0.1).toFixed(10)) // 結果為 3 parseFloat((9.7 * 100).toFixed(10)) // 結果為 970 parseFloat((2.22 + 0.1).toFixed(10)) // 結果為 2.32

在老版本的IE瀏覽器(IE 6,7,8)中,toFixed()方法返回值不一定準確。所以這個方法以前很少用。以至于網上搜索出來的結果大都是下面這些方法。

還有一些其他的解決方案,簡單的說需要將浮點數轉換字符串,分隔成為整數部分和小數部分,小數部分再轉換為整數,計算結果后,再轉換為浮點數。這過程有點復雜…,網上找一下:

加法函數

/** ** 加法函數,用來得到精確的加法結果 ** 說明: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);};

減法函數

/** ** 減法函數,用來得到精確的減法結果 ** 說明: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);};

乘法函數

/** ** 乘法函數,用來得到精確的乘法結果 ** 說明: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);};

除法函數

/**  ** 除法函數,用來得到精確的除法結果 ** 說明: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);};

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
97久久精品国产| 91丨九色丨国产在线| 国产精品露脸自拍| 午夜欧美大片免费观看| 欧美怡红院视频一区二区三区| 亚洲日本欧美中文幕| 国产精品久久久久久av福利软件| 欧美成人精品h版在线观看| 97久久久久久| 亚洲欧美日韩精品久久亚洲区| 亚洲www永久成人夜色| 欧美精品手机在线| 欧美色播在线播放| 亚洲综合色激情五月| 国产精品亚洲аv天堂网| 亚洲黄色免费三级| 欧美激情国产精品| 国产丝袜一区二区三区| 疯狂做受xxxx欧美肥白少妇| 国产精品成人在线| 在线精品国产成人综合| 亚洲free性xxxx护士hd| 欧美电影免费观看网站| 欧美国产日韩视频| 大荫蒂欧美视频另类xxxx| 欧美精品在线极品| 亚洲人成电影在线观看天堂色| 91深夜福利视频| 国模精品一区二区三区色天香| 亚洲午夜av久久乱码| 日韩成人av在线播放| 久久久综合av| 欧美中文字幕在线视频| 亚洲第一网站免费视频| 国产精品日韩一区| 亚洲日韩中文字幕| 日av在线播放中文不卡| 中文字幕不卡在线视频极品| 最新69国产成人精品视频免费| 国产一区二区三区免费视频| 最近2019年好看中文字幕视频| 国产一区二区三区在线| 亚洲香蕉成人av网站在线观看| 国产视频在线一区二区| 色www亚洲国产张柏芝| 久久99国产精品久久久久久久久| 7m精品福利视频导航| 亚洲女人天堂色在线7777| 久久精品久久久久电影| 九九热最新视频//这里只有精品| 亚洲男人7777| 成人黄色网免费| 久久91亚洲人成电影网站| 国产日韩精品在线播放| 九九九热精品免费视频观看网站| 成人美女免费网站视频| 97精品国产97久久久久久春色| 91在线观看免费高清完整版在线观看| 欧美电影免费观看网站| 日韩视频免费大全中文字幕| 国产精品久久二区| 久久久久久久亚洲精品| 欧美人与物videos| 国产精品91视频| 国产v综合v亚洲欧美久久| 91久久国产精品| 免费91在线视频| 国产精品扒开腿做爽爽爽的视频| 亚洲国产精品yw在线观看| 精品国产成人在线| 久久久久久久成人| 国产免费亚洲高清| 欧美性精品220| 国模gogo一区二区大胆私拍| 欧美日韩亚洲精品一区二区三区| 日韩黄色av网站| 亚洲综合色激情五月| 日韩欧美国产免费播放| 久久亚洲综合国产精品99麻豆精品福利| 国产一区欧美二区三区| 原创国产精品91| 日韩综合中文字幕| 狠狠综合久久av一区二区小说| 97热精品视频官网| 国产精品夫妻激情| 日韩精品在线免费观看视频| 欧美猛交ⅹxxx乱大交视频| 亚洲精品97久久| 国产小视频国产精品| 国产第一区电影| 国产精品视频一区二区高潮| 亚洲欧美日韩精品久久亚洲区| 亚洲色图校园春色| 91精品在线观| 亚洲欧美另类在线观看| 欧美一区二区三区……| 欧美色道久久88综合亚洲精品| 亚洲美女又黄又爽在线观看| 欧美日在线观看| 亚洲精品一区二区久| 亚洲成人激情视频| 色婷婷综合久久久久| 97精品国产97久久久久久春色| 欧美日韩国产综合视频在线观看中文| 久久人人爽人人| 日韩美女视频在线观看| 亚洲成年人在线播放| 午夜精品久久久久久久白皮肤| 日韩av在线导航| 在线视频日本亚洲性| 亚洲高清福利视频| 色婷婷av一区二区三区在线观看| 久久久久久999| 两个人的视频www国产精品| 4438全国亚洲精品在线观看视频| 国产国产精品人在线视| 色综合老司机第九色激情| 日韩a**站在线观看| 国产精品一区二区女厕厕| 日韩专区在线播放| 91精品国产网站| 青青草精品毛片| 久久精品91久久久久久再现| 日韩欧美成人网| 久久综合亚洲社区| 国产91精品在线播放| 亚洲美女在线观看| 国产一区二区三区在线视频| 久久影院在线观看| 久久久久久噜噜噜久久久精品| 欧美日产国产成人免费图片| 国产成人短视频| 亚洲天堂av高清| 国产精品黄页免费高清在线观看| 日韩在线视频免费观看高清中文| 国产亚洲精品日韩| 欧美日韩精品国产| 亚洲福利在线视频| 国产成人自拍视频在线观看| 亚洲图片制服诱惑| 欧美国产欧美亚洲国产日韩mv天天看完整| 欧洲亚洲免费在线| 国产69精品久久久久久| 欧美不卡视频一区发布| 91久久久久久久久久久久久| 日韩欧美国产成人| 日韩欧美一区二区三区| 欧美一级视频免费在线观看| 欧美黄网免费在线观看| 国产在线观看不卡| 国产v综合v亚洲欧美久久| 国产男女猛烈无遮挡91| 日韩精品在线观| 色妞一区二区三区| 97在线免费观看| 国产精品久久二区| 欧美另类极品videosbest最新版本| 色综合老司机第九色激情| 在线日韩欧美视频| 国产精品青草久久久久福利99| 成人精品视频久久久久| 成人激情综合网| 久久亚洲国产成人| 国产视频丨精品|在线观看|