js實現小數點四舍五入


js實現小數點四舍五入

其實這個問題,在之前的面試中被提問到了,由於筆者平時都是用原生的toFixed()的方法來保留小數點,所以當時並沒有回答出來這個問題,嗚嗚嗚. 😹
現在突然想起了這個問題,就研究一下吧。

最簡單的實現方法

可以使用Math對象的一些方法來實現,這個比較簡單,主要用到了Math.round和一些簡單的乘除法運算。例子
思路:
1. 先把數值轉成只有一位小數點的數值
2. 利用Math.round方法四舍五入(關鍵)
3. 最后通過乘除法運算等到想要的小數點位數


function toFixed(num,decimal){
    if(isNaN(num)){
        return 0;
    }
    num = num-0;
    var p1 = Math.pow(10, decimal + 1);
    var p2 = Math.pow(10, decimal);
    console.log(num * p1 / 10);
    console.log(Math.round(num * p1 / 10));
    return (Math.round(num * p1 / 10) / p2).toFixed(decimal); //思考一下,為什么要除10?
}

運行一下上面的代碼,其實有隱藏的bug... 💔


toFixed(2.555,2) //2.56

toFixed(4100.065,2) //4100.06 ???

console.log(4100065/10) //410006.49999999994  這就是bug的答案

0.1+0.2=? //0.30000000000000004

所謂的隱藏bug,就是js編程語言的小數點精度問題,所以上面那個除於10 只是在一定的范圍內有效,過了這個范圍,還是會出現精度問題...

用字符串處理

既然小數點進行運算會出現問題,那我們換一種思路,用字符串來處理。例子 😄
思路:
1. 把數字轉成字符串,然后把小數點移動到倒數第二位。(模擬只有一位小數點)
2. 還是用到Math.round來四舍五入
3. 重復第一個步驟,不過把小數點移動到(你要保留多少位小數點)


function toFixed(num,decimal){
    if(isNaN(num)){
        return 0;
    }
    var strnum = num+'';
    var arr = strnum.split('.');
    if(arr.length<2){
        return num.toFixed(decimal);
    }

    strnum = arr.join('');

    var strnum2 = strnum.slice(0,-1)+'.'+strnum.slice(-1);

    var result = Math.round(strnum2-0)+'';

    if(arr[1].length==decimal){
        result+='0'; //如果小數點的個數剛好等於要保留的小數點個數,要補0
    }

    return result.slice(0,-decimal)+'.'+result.slice(-decimal)
}

2020-04 更新

上面的字符串處理不夠好,下面補充個新的邏輯方式:

  1. 把數字轉成字符,並記錄.小數點的位置;如果沒有小數點,則直接在后面補0;
  2. 通過小數點的位置,計算出原數字有多少位小數(oldPointNum);把小數點去掉並且把字符串轉成數組;
  3. 通過比較oldPointNum和n(要保留的位數);如果oldPointNum<n,直接補0;否則下一步
  4. 比較數組倒數(i =oldPointNum-n)的數字是否>=5;是則進一位;i++;循環該步驟(核心),用這一步來模擬四舍五入。

const toFixed = (number, n) => {
  let numberStr = number + "";
  let reg = /^(-|\+)?(\d+(\.\d*)?|\.\d+)$/i;
  if(!reg.test(numberStr)) {
      console.error('輸入的數字格式不對');
      return;
  }
  let sign = numberStr.charAt(0) === '-' ? (numberStr=numberStr.slice(1),-1):1; // 判斷是否是負數
  let pointIndex = numberStr.indexOf("."); // 記錄小數點的位置
  if (pointIndex > -1) {
    numberStr = numberStr.replace(".", "");
  } else { // 沒有小數點直接添加補0;
    numberStr += ".";
    numberStr+=new Array(n).join('0');
    return numberStr;
  }
  let numberArray = numberStr.split(""); //轉成數組
  let len = numberArray.length;
  let oldPointNum = len - pointIndex; // 獲取原數據有多少位小數
  if (oldPointNum < n) { // 要保留的小數點比原來的要大,直接補0
    while (n - oldPointNum > 0) {
      numberArray.push(0);
      n--;
    }
  } else if (oldPointNum > n) { // 模擬四舍五入
    
    let i = oldPointNum - n; // 從倒數第i個數字開始比較
    let more = numberArray[len - i] >= 5 ? true : false;
    while (more) {
      i++;
      more = +numberArray[len - i] + 1 === 10 ? true : false; // 進位后判斷是否等於10,是則繼續進位
      numberArray[len - i] = more&&i!==(len+1) ? 0 : +numberArray[len - i] + 1; // 其他位置的數字進位直接變成0,第一位的例外
      console.log(i, len);
    }
    numberArray.length = len- (oldPointNum-n); // 截取多余的小數
  }
  numberArray.splice(pointIndex, 0, ".");
  return sign===-1?'-'+numberArray.join(""):numberArray.join("");
};

ps :上面的代碼有點臃腫,其實可以通過正則來簡化,以后有空修改。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM