JS中toFixed(2)精度問(wèn)題的原因以及解決辦法
toFixed() 方法可把 Number 四舍五入為指定小數(shù)位數(shù)的數(shù)字。例如將數(shù)據(jù)Num保留2位小數(shù),則表示為:toFixed(Num);但是其四舍五入的規(guī)則與數(shù)學(xué)中的規(guī)則不同,使用的是銀行家舍入規(guī)則,銀行家舍入:所謂銀行家舍入法,其實(shí)質(zhì)是一種四舍六入五取偶(又稱四舍六入五留雙)法。具體規(guī)則如下:簡(jiǎn)單來(lái)說(shuō)就是:四舍六入五考慮,五后非零就進(jìn)一,五后為零看奇偶,五前為偶應(yīng)舍去,五前為奇要進(jìn)一。
經(jīng)測(cè)試發(fā)現(xiàn),在chorme下面,并沒(méi)有完全遵守這個(gè)規(guī)則,尤其是5的后面沒(méi)有數(shù)字的時(shí)候,不是這么判斷的,如下:
var b = 1.335 b.toFixed(2) "1.33" var b = 1.345 b.toFixed(2) "1.34" var b = 1.355 b.toFixed(2) "1.35" var b = 1.365 b.toFixed(2) "1.36" var b = 1.375 b.toFixed(2) "1.38" var b = 1.385 b.toFixed(2) "1.39"
可以發(fā)現(xiàn)在chorme下沒(méi)有完全去遵循這個(gè)規(guī)律,或許它有自己的算法,但是畢竟它沒(méi)有遵循通用的銀行家算法,所以tofixed這個(gè)方法在涉及到金錢計(jì)算的業(yè)務(wù)中還是少用.
總而言之:不論引入toFixed解決浮點(diǎn)數(shù)計(jì)算精度缺失的問(wèn)題也好,它有沒(méi)有使用銀行家舍入法也罷,都是為了解決精度的問(wèn)題,但是又離不開(kāi)二進(jìn)制浮點(diǎn)數(shù)的環(huán)境,但至少他幫助我們找到了問(wèn)題所在,從而讓我們有解決方法。
一開(kāi)始的辦法是把要四舍五入的后一位單獨(dú)拎出來(lái)單獨(dú)判斷。
解決方法:
通過(guò)重寫toFixed方法:
Number.prototype.toFixed = function (n) { let result = number.toString(); const arr = result.split('.'); const integer = arr[0]; const decimal = arr[1]; result = integer + '.' + decimal.substr(0, n); const last = decimal.substr(n, 1);
// 四舍五入,轉(zhuǎn)換為整數(shù)再處理,避免浮點(diǎn)數(shù)精度的損失
if (parseInt(last, 10) >= 5) { const x = Math.pow(10, n); result = ((parseFloat(result) * x) + 1) / x; result = result.toFixed(n); } return result; }
然后又發(fā)現(xiàn)計(jì)算機(jī)二進(jìn)制編碼導(dǎo)致的精度問(wèn)題,詳見(jiàn)上一篇博客。
自己debugger,發(fā)現(xiàn)頁(yè)面中的js進(jìn)了死循環(huán)。很明顯問(wèn)題出在toFixed中回調(diào)了toFixed,結(jié)果沒(méi)有走出來(lái),繼續(xù)debugger,又有了驚人的發(fā)現(xiàn)。以下是控制臺(tái)測(cè)試:
console.log(2.115 * 100) // 211.50000000000003 console.log(2.0115 * 1000) // 2011.4999999999998
既然你一直進(jìn)入循環(huán),我就手動(dòng)把你拉出來(lái)。
result = (Math.round((parseFloat(result)) * x) + 1) / x;
最終完整的重寫toFixed的方法
// toFixed兼容方法 Number.prototype.toFixed = function (n) { if (n > 20 || n < 0) { throw new RangeError('toFixed() digits argument must be between 0 and 20'); } const number = this; if (isNaN(number) || number >= Math.pow(10, 21)) { return number.toString(); } if (typeof (n) == 'undefined' || n == 0) { return (Math.round(number)).toString(); } let result = number.toString(); const arr = result.split('.'); // 整數(shù)的情況 if (arr.length < 2) { result += '.'; for (let i = 0; i < n; i += 1) { result += '0'; } return result; } const integer = arr[0]; const decimal = arr[1]; if (decimal.length == n) { return result; } if (decimal.length < n) { for (let i = 0; i < n - decimal.length; i += 1) { result += '0'; } return result; } result = integer + '.' + decimal.substr(0, n); const last = decimal.substr(n, 1); // 四舍五入,轉(zhuǎn)換為整數(shù)再處理,避免浮點(diǎn)數(shù)精度的損失 if (parseInt(last, 10) >= 5) { const x = Math.pow(10, n); result = (Math.round((parseFloat(result) * x)) + 1) / x; result = result.toFixed(n); } return result; }
總結(jié)
到此這篇關(guān)于JS中toFixed(2)精度問(wèn)題的原因以及解決辦法的文章就介紹到這了,更多相關(guān)js toFixed(2)精度問(wèn)題解決內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Javscript刪除數(shù)組中指定元素并返回新數(shù)組
把數(shù)組中某個(gè)值刪除,并返回新數(shù)組,需要遍歷舊數(shù)組找到要?jiǎng)h除的元素,下面有個(gè)不錯(cuò)的示例,大家可以參考下2014-03-03創(chuàng)建與框架無(wú)關(guān)的JavaScript插件
這篇文章主要介紹了創(chuàng)建與框架無(wú)關(guān)的JavaScript插件,幫助大家更好的理解和使用JavaScript,感興趣的朋友可以了解下2020-12-12詳細(xì)聊聊JavaScript是如何影響DOM樹(shù)構(gòu)建的
DOM (Document Object Model) 的全稱是文檔對(duì)象模型,它可以以一種獨(dú)立于平臺(tái)和語(yǔ)言的方式訪問(wèn)和修改一個(gè)文檔的內(nèi)容和結(jié)構(gòu),這篇文章主要給大家介紹了關(guān)于JavaScript是如何影響DOM樹(shù)構(gòu)建的相關(guān)資料,需要的朋友可以參考下2021-08-08兼容ie和firefox的鼠標(biāo)經(jīng)過(guò)(onmouseover和onmouseout)實(shí)現(xiàn)--簡(jiǎn)短版
兼容ie和firefox的鼠標(biāo)經(jīng)過(guò)(onmouseover和onmouseout)實(shí)現(xiàn)--簡(jiǎn)短版...2007-11-11JavaScript為事件句柄綁定監(jiān)聽(tīng)函數(shù)實(shí)例詳解
這篇文章主要介紹了JavaScript為事件句柄綁定監(jiān)聽(tīng)函數(shù)的方法,結(jié)合實(shí)例詳細(xì)分析了常見(jiàn)的事件句柄綁定監(jiān)聽(tīng)函數(shù)的實(shí)現(xiàn)技巧,并實(shí)例講解了跨瀏覽器的實(shí)現(xiàn)方法,需要的朋友可以參考下2015-12-12js中如何對(duì)嵌套數(shù)組進(jìn)行filter過(guò)濾
這篇文章主要介紹了js中如何對(duì)嵌套數(shù)組進(jìn)行filter過(guò)濾問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06