1. 程式人生 > >JS toFixed(銀行家舍入法)及其缺陷和解決方法

JS toFixed(銀行家舍入法)及其缺陷和解決方法

所謂銀行家舍入法,其實質是一種四捨六入五取偶(又稱四捨六入五留雙)法。

據說,大部分的程式設計軟體都使用的是這種方法,也算是一種國際標準。 所謂銀行家舍入法,其實質是一種四捨六入五取偶(又稱四捨六入五留雙)法。其規則是:當捨去位的數值小於5時,直接捨去該位;當捨去位的數值大於等於6時,在捨去該位的同時向前位進一;當捨去位的數值等於5時,如果前位數值為奇,則在捨去該位的同時向前位進一,如果前位數值為偶,則直接捨去該位。

簡單的說,就是:四捨六入五考慮,五後非零就進一,五後為零看奇偶,五前為偶應捨去,五前為奇要進一

 

定義和用法

toFixed() 方法可把 Number 四捨五入為指定小數位數的數字。

語法

NumberObject.toFixed(num)
引數 描述
num 必需。規定小數的位數,是 0 ~ 20 之間的值,包括 0 和 20,有些實現可以支援更大的數值範圍。如果省略了該引數,將用 0 代替。

返回值

返回 NumberObject 的字串表示,不採用指數計數法,小數點後有固定的 num 位數字。如果必要,該數字會被舍入,也可以用 0 補足,以便它達到指定的長度。如果 num 大於 le+21,則該方法只調用 NumberObject.toString(),返回採用指數計數法表示的字串。

丟擲

當 num 太小或太大時丟擲異常 RangeError。0 ~ 20 之間的值不會引發該異常。有些實現支援更大範圍或更小範圍內的值。

當呼叫該方法的物件不是 Number 時丟擲 TypeError 異常。

 

以下轉自http://www.chengfeilong.com/toFixed  toFixed計算錯誤(依賴銀行家舍入法的缺陷)解決方法

 

5後為零(5為最後一位): 由於這種情況比較特殊,是toFixed方法出現計算錯誤的情況。

var num = 0.005;
console.log(num.toFixed(2));  //0.01
var num = 0.015;
console.log(num.toFixed(2));  //0.01

解決方法

通過重寫toFixed的方法:

Number.prototype.toFixed = function(length)
        {
            var carry = 0; //存放進位標誌
            var num,multiple; //num為原浮點數放大multiple倍後的數,multiple為10的length次方
            var str = this + ''; //將呼叫該方法的數字轉為字串
            var dot = str.indexOf("."); //找到小數點的位置
            if(str.substr(dot+length+1,1)>=5) carry=1; //找到要進行舍入的數的位置,手動判斷是否大於等於5,滿足條件進位標誌置為1
            multiple = Math.pow(10,length); //設定浮點數要擴大的倍數
            num = Math.floor(this * multiple) + carry; //去掉舍入位後的所有數,然後加上我們的手動進位數
            var result = num/multiple + ''; //將進位後的整數再縮小為原浮點數
            /*
            * 處理進位後無小數
            */
            dot = result.indexOf(".");
            if(dot < 0){
                result += '.';
                dot = result.indexOf(".");
            }
            /*
            * 處理多次進位
            */
            var len = result.length - (dot+1);
            if(len < length){
                for(var i = 0; i < length - len; i++){
                    result += 0;
                }
            }
            return result;
        }

該方法的大致思路是首先找到舍入位,判斷該位置是否大於等於5,條件成立手動進一位,然後通過引數大小將原浮點數放大10的引數指數倍,然後再將包括舍入位後的位數利用floor全部去掉,根據我們之前的手動進位來確定是否進位。