日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

php 精度问题怎么解决,JavaScript 中精度问题以及解决方案

發(fā)布時(shí)間:2025/3/11 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 php 精度问题怎么解决,JavaScript 中精度问题以及解决方案 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

JavaScript 中的數(shù)字按照 IEEE 754 的標(biāo)準(zhǔn),使用 64 位雙精度浮點(diǎn)型來表示。其中符號(hào)位 S,指數(shù)位 E,尾數(shù)位M分別占了 1,11,52 位,并且在 ES5 規(guī)范 中指出了指數(shù)位E的取值范圍是 [-1074, 971]。

精度問題匯總

想用有限的位來表示無窮的數(shù)字,顯然是不可能的,因此會(huì)出現(xiàn)一些列精度問題:

浮點(diǎn)數(shù)精度問題,比如 0.1 + 0.2 !== 0.3

大數(shù)精度問題,比如 9999 9999 9999 9999 == 1000 0000 0000 0000 1

toFixed 四舍五入結(jié)果不準(zhǔn)確,比如 1.335.toFixed(2) == 1.33

浮點(diǎn)數(shù)精度和 toFixed 其實(shí)屬于同一類問題,都是由于浮點(diǎn)數(shù)無法精確表示引起的,如下:

(1.335).toPrecision(20); // "1.3349999999999999645"

而關(guān)于大數(shù)精度問題,我們可以先看下面這個(gè)代碼片段:

// 能精確表示的整數(shù)范圍上限,S為1個(gè)0,E為11個(gè)0,S為53個(gè)1

Math.pow(2, 53) - 1 === Number.MAX_SAFE_INTEGER // true

// 能精確表示的整數(shù)范圍下限,S為1個(gè)1,E為11個(gè)0,S為53個(gè)1

-(Math.pow(2, 53) - 1) === Number.MIN_SAFE_INTEGER // true

// 能表示的最大數(shù)字,S為1個(gè)0,E為971,S為53個(gè)1

(Math.pow(2, 53) - 1) * Math.pow(2, 971) === Number.MAX_VALUE // true

// 能表示的最接近于0的正數(shù),S為1個(gè)0,E為-1074,S為0

Math.pow(2, -1074) === Number.MIN_VALUE // true

通過以上可以明白,[MIN_SAFE_INTEGER, MAX_SAFE_INTEGER] 的整數(shù)都可以精確表示,但是超出這個(gè)范圍的整數(shù)就不一定能精確表示。這樣就會(huì)產(chǎn)生所謂的大數(shù)精度丟失問題。

解決思路

首先考慮的是如何解決浮點(diǎn)數(shù)運(yùn)算的精度問題,有 3 種思路:

考慮到每次浮點(diǎn)數(shù)運(yùn)算的偏差非常小(其實(shí)不然),可以對(duì)結(jié)果進(jìn)行指定精度的四舍五入,比如可以parseFloat(result.toFixed(12));

將浮點(diǎn)數(shù)轉(zhuǎn)為整數(shù)運(yùn)算,再對(duì)結(jié)果做除法。比如0.1 + 0.2,可以轉(zhuǎn)化為(1*2)/3。

把浮點(diǎn)數(shù)轉(zhuǎn)化為字符串,模擬實(shí)際運(yùn)算的過程。

先來看第一種方案,在大多數(shù)情況下,它可以得到正確結(jié)果,但是對(duì)一些極端情況,toFixed 到 12 是不夠的,比如:

210000 * 10000 * 1000 * 8.2 // 17219999999999.998

parseFloat(17219999999999.998.toFixed(12)); // 17219999999999.998,而正確結(jié)果為 17220000000000

上面的情況,如果想讓結(jié)果正確,需要 toFixed(2),這顯然是不可接受的。

再看第二種方案,比如 number-precision 這個(gè)庫就是使用的這種方案,但是這也是有問題的,比如:

// 這兩個(gè)浮點(diǎn)數(shù),轉(zhuǎn)化為整數(shù)之后,相乘的結(jié)果已經(jīng)超過了 MAX_SAFE_INTEGER

123456.789 * 123456.789 // 轉(zhuǎn)化為 (123456789 * 123456789)/1000000,結(jié)果是 15241578750.19052

所以,最終考慮使用第三種方案,目前已經(jīng)有了很多較為成熟的庫,比如 bignumber.js,decimal.js,以及big.js等。我們可以根據(jù)自己的需求來選擇對(duì)應(yīng)的工具。并且,這些庫不僅解決了浮點(diǎn)數(shù)的運(yùn)算精度問題,還支持了大數(shù)運(yùn)算,并且修復(fù)了原生toFixed結(jié)果不準(zhǔn)確的問題。

題外話

還有另外一個(gè)與 JavaScript 計(jì)算相關(guān)的問題,即 Math.round(x),它雖然不會(huì)產(chǎn)生精度問題,但是它有一點(diǎn)小陷阱容易忽略。下面是它的舍入的策略:

如果小數(shù)部分大于 0.5,則舍入到下一個(gè)絕對(duì)值更大的整數(shù)。

如果小數(shù)部分小于 0.5,則舍入到下一個(gè)絕對(duì)值更小的整數(shù)。

如果小數(shù)部分等于 0.5,則舍入到下一個(gè)正無窮方向上的整數(shù)。

所以,對(duì) Math.round(-1.5),其結(jié)果為 -1,這可能不是我們想要的結(jié)果。

當(dāng)然,上面提到的 big.js 等庫,都提供了自己的 round 函數(shù),并且可以指定舍入規(guī)則,以避免這個(gè)問題。

總結(jié)

以上是生活随笔為你收集整理的php 精度问题怎么解决,JavaScript 中精度问题以及解决方案的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。