JavaScript四捨五入的改進

愛coding的小黑發表於2019-02-16

前言

最近的兩個專案中都有涉及到資料統計的部分,一般來說金額的資料都是選擇儲存2位小數,以前是使用JavaScript原生物件Number的toFixed方法。但是在測試中出現了3.235.toFixed(2) = 3.23的問題。查了下資料發現是因為浮點數的儲存產生的問題。最後就自己封裝了一個函式來解決這個問題。

1. toFixed失去準確性的原因

關於浮點數的儲存我瞭解不多,這裡推薦這個文章給需要的同學JavaScript 浮點數陷阱及解法

2. 封裝toFixed

2-1 實現思路

  • 大體的思路是先分2部分,一是整數部分。整數部分不需要對值進行修改,為了和Number.toFixed保持一致,需要補上對應的0 (8.toFixed(2) => 8.00);
  • 小數部分要做3個判斷,當前小數後位數與要儲存的位數進行比較。等於的直接返回,當前小數後位數小於要儲存的位數就捨棄掉多餘的部分。最後一種情況要針對正負數進行不同的處理,詳情見下方程式碼。
  • 注意:返回的結果都是字串。

2-2 程式碼

let tofixed = (value, holdLen) => {
    value = value.toString();
    let dotIndex = value.indexOf(".");
    //判斷是否為整數
    if (dotIndex === -1) {
        //少幾位就補幾位0
        let integerStr = ".";
        for (let i = 0; i < holdLen; i++) {
            integerStr = integerStr + `0`;
        }
        return value + integerStr;
    }
    //獲取小數點前後的字串
    let dotBefore = value.split(".")[0];
    let dotAfter = value.split(".")[1];
    //小數點後與要保留的位數進行判斷出來
    let result = "";
    if (dotAfter.length === holdLen) {
        result = value;
    } else if (dotAfter.length < holdLen) {
        let forlength = holdLen - dotAfter.length
        //少幾位就補幾位0
        for (let i = 0; i < forlength; i++) {
            dotAfter = dotAfter + `0`;
        }
        result = dotBefore + "." + dotAfter;
    } else {
        //獲取到要四捨五入的位置後一個數字的值
        let digit = value.substr(dotIndex + holdLen + 1, 1);
        if (digit >= 5) {
            let temp = Math.pow(10, 0 - holdLen);
            //負數和正數的四捨五入判斷
            parseFloat(value) > 0 ? value = parseFloat(value) + temp : value = parseFloat(value) - temp;
            value = value.toString();
        }
        result = value.substr(0, dotIndex + holdLen + 1);
    }
    return result;
}
console.log(tofixed(1.335, 2));
console.log(tofixed(2.1, 3));
console.log(tofixed(-8.546, 2));
console.log(tofixed(-9, 3));

//列印結果
"1.34"
"2.100"
"-8.55"
"-9.000"

我的處理辦法很粗糙,希望各位多多給出意見。

相關文章