You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解决JavaScript中toFixed和Math.round的跨浏览器舍入错误问题

JavaScript中精确舍入35.855至两位小数的解决方案

问题根源

JavaScript采用二进制浮点数存储数值,35.855无法被精确表示,实际存储的是一个接近它的近似值。不同浏览器对这个近似值的计算细节存在差异:

  • Chrome中存储的近似值略小于35.855,乘100后为3585.4999999999995,Math.round后得到3585,最终结果35.85
  • IE9中存储的近似值更接近35.855,乘100后为3585.5,Math.round后得到3586,最终结果35.86

原生Math.round和toFixed依赖二进制浮点数计算,容易因精度误差导致舍入结果不一致,需要自定义精确舍入逻辑。

通用解决方案

方法1:使用BigInt实现精确舍入

利用BigInt避免浮点数运算的精度丢失,同时添加极小值修正浮点数近似误差:

function preciseRound(num, decimals) {
  const power = 10 ** decimals;
  // 加Number.EPSILON*power修正浮点数精度偏差
  const scaled = num * power + Number.EPSILON * power;
  return Number((BigInt(Math.round(scaled)) / BigInt(power)).toString());
}

// 测试用例
console.log(preciseRound(35.855, 2)); // 输出35.86
console.log(preciseRound(2.5, 0)); // 输出3
console.log(preciseRound(1.2345, 3)); // 输出1.235

方法2:字符串解析实现精确舍入

若环境不支持BigInt,可通过字符串解析手动处理进位逻辑,完全基于十进制运算:

function preciseRound(num, decimals) {
  const numStr = num.toString();
  if (!numStr.includes('.')) return Number(numStr);
  
  const [integerPart, decimalPart] = numStr.split('.');
  // 截取目标小数位+1位,用于判断是否进位
  const targetDigits = decimalPart.slice(0, decimals + 1);
  let resultInt = integerPart;
  let resultDec = targetDigits.slice(0, decimals);
  const nextDigit = parseInt(targetDigits[decimals], 10) || 0;

  if (nextDigit >= 5) {
    let carry = 1;
    // 处理小数部分进位
    const decArr = resultDec.split('').reverse();
    for (let i = 0; i < decArr.length && carry; i++) {
      const newDigit = parseInt(decArr[i], 10) + carry;
      if (newDigit === 10) {
        decArr[i] = '0';
        carry = 1;
      } else {
        decArr[i] = newDigit.toString();
        carry = 0;
      }
    }
    resultDec = decArr.reverse().join('');

    // 处理整数部分进位(若小数进位后仍有剩余进位)
    if (carry) {
      const intArr = resultInt.split('').reverse();
      for (let i = 0; i < intArr.length && carry; i++) {
        const newDigit = parseInt(intArr[i], 10) + carry;
        if (newDigit === 10) {
          intArr[i] = '0';
          carry = 1;
        } else {
          intArr[i] = newDigit.toString();
          carry = 0;
        }
      }
      resultInt = carry ? '1' + intArr.reverse().join('') : intArr.reverse().join('');
    }
  }

  // 去除小数末尾的无效0,若小数部分为空则仅返回整数
  resultDec = resultDec.replace(/0+$/, '');
  return resultDec ? Number(`${resultInt}.${resultDec}`) : Number(resultInt);
}

// 测试用例
console.log(preciseRound(35.855, 2)); // 输出35.86
console.log(preciseRound(1.005, 2)); // 输出1.01
console.log(preciseRound(99.995, 2)); // 输出100

内容的提问来源于stack exchange,提问作者Sercan Samet Savran

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 04:53:36