js数字四舍五入,toFixed() 方法遵循的规则你知道吗?

网安智编 厦门萤点网络科技 2026-05-21 00:16 16 0
() 方法将数值转换为一个字符串,该字符串表示该数值与指定小数位数的最近近似值。当需要四舍五入时,它遵循IEEE 754标准中的四舍五入规则,这与一般的数学四舍五入规则有所不同。 语法: .() :指定小数位数。 () 会将数字四舍五入到指...

() 方法将数值转换为一个字符串,该字符串表示该数值与指定小数位数的最近近似值。当需要四舍五入时,它遵循IEEE 754标准中的四舍五入规则,这与一般的数学四舍五入规则有所不同。

语法:

.()

:指定小数位数。

() 会将数字四舍五入到指定的小数位数,并返回一个字符串。如果小数位数不足,会用 0 填充。

() 遵循银行家舍入法,但有些时候和好像和银行家舍入法的结果不同,其实这是我们误会 () 了,主要是因为 浮点数在用二进制中存储时有精度误差导致 () 用银行家四舍五入时不准。

银行家舍入法

我国金融系统的大部分算法就是用四舍五入,国际上欧盟委员会对换汇时的舍入规定也是我们常见的四舍五入。

真正广泛采用银行家舍入法的,是需要更小误差的科学和计算机系统,因为多次舍入时银行家舍入法会比传统舍入法误差更小,因此银行家舍入法也叫统计学家舍入('s )、无偏舍入( )。现在大部分编程软件的默认舍入都是银行家舍入法,比如 c/c++、、php、go,英特尔处理器用的也是银行家舍入。

规则四舍六入五取偶:

•(1)被修约的数字小于5时,该数字舍去;

•(2)被修约的数字大于5时,则进位;

•(3)被修约的数字等于5时,要看5前面的数字,若是奇数则进位,若是偶数则将5舍掉,即修约后末尾数字都成为偶数;若5的后面还有不为“0”的任何数,则此时无论5的前面是奇数还是偶数,均应进位。

示例:

•9.8249=9.82,9.82671=9.83

•9.835=9.84,9.8351 =9.84

•9.825=9.82,9.82501=9.83

简单的说,就是:四舍六入五考虑,五后非空就进一,五后为空看奇偶,五前为偶应舍去,五前为奇要进一

测试银行家舍入法正常情况:

// 5 后非 0 进位后舍去

const err1 = 22.4451

.log('err1', err1.(2)); // 22.45

// 5 后非 0 进位后舍去

const err1 = 22.

.log('err1', err1.(2)); // 22.45

// 5后无,5前一位为奇数 进位

const err1 = 22.475

.log('err1', err1.(2)); // 22.48

// 5后无,5前一位为偶数 舍去

const err1 = 22.485

.log('err1', err1.(2)); // 22.48

测试异常情况:

// 5后无,5前一位为奇数 进位

const err1 = 22.415

.log('err1', err1.(2)); // 22.41

// 5后无,5前一位为奇数 进位

const err1 = 22.455

.log('err1', err1.(2)); // 22.45

// 5后无,5前一位为偶数 舍去

const err1 = 22.445

.log('err1', err1.(2)); // 22.45

// 5后无,5前一位为偶数 舍去

const err1 = 22.425

.log('err1', err1.(2)); // 22.43

// 5后无,5前一位为偶数 舍去

const err1 = 22.405

.log('err1', err1.(2)); // 22.41

// 5后无,5前一位为奇数 进位

const err1 = 0.015

.log('err1', err1.(2)); // 0.01

注意:这个挺吓人的,0.015 变成 0.01 慎用啊

原因分析:

const err1 = 1.005

.log('err1', err1.(2)); // "1.00"(预期是 "1.01")

原因:浮点数在内存中的实际值可能略小于表面值。例如,`1.005` 实际存储为 `1.`,导致四舍五入错误。

可以用下面方法查询浮点数在内存中存的值

    function getDecimalValue(floatNum) {
      // 这里不用 Decimal.toBinary, 因为toString 更准确
      const binaryString = '0b' + floatNum.toString(2)  // 将小数转为二进制
      // console.log(binaryString)
      let decimalValue = new Decimal(binaryString, 2).toString(); // 直接从二进制转换并创建Decimal对象
      console.log(decimalValue);
      return Number(decimalValue);
    }

然后重新测一下上面的值发现结果都遵循银行家舍入了。

const err1 = 22.415

// 22.90625

.log((err1).(2)); // 22.41

const err1 = 22.455

// 22.

.log((err1).(2)); // 22.45

const err1 = 22.445

// 22.

.log((err1).(2)); // 22.45

const err1 = 22.425

// 22.

.log((err1).(2)); // 22.43

const err1 = 22.425

// 22.

.log((err1).(2)); // 22.41

const err1 = 0.015

// 0.

.log((err1).(2)); // 0.01

javascript toFixed 银行家舍入法 浮点数精度误差_js数字四舍五入

但是浮点数有数度问题怎么办呢,本人觉得可以考虑其它方法,自己写一个方法或是用下面方法

使用正常四舍五入

看到网上有很多这么写的,其实是不对的,不加 ,这个结果是 1,没有 .00

    function roundUp(num, digits) {
      const factor = 10 ** digits;
      return (Math.round(num * factor) / factor).toFixed(digits);
    }
    const test = 1.005
    console.log(roundUp(test, 2));

上面结果还是 1.00 ,不是 1.01,还是有精度问题

因为 1.005 存储在内存中值是 1.

乘以 100 后是 100......... 四舍五入后还是 100 而不是 101,所以还是使用高精度库函数

也有用下面这种方法的,但是用 23.005 保留 2 位小数, 测试就不准了

    function roundUp(num, digits) {
      const factor = 10 ** digits
      const roundAdd1 = Math.round(num * factor * 10)
      const round = Math.round(roundAdd1 / 10)
      return (round / factor).toFixed(digits)
    }

Big.js

    function roundUp(num, precision = 0) {
      const bigNum = new Big(num).round(precision)
      return bigNum.toNumber().valueOf()
    }
    const test = 1.005
    console.log(new Big(test).toNumber().valueOf()); // 1.005
    console.log(roundUp(test, 2)); // 1.01

.js

查看了源码,.js 的 默认用的是正常四舍五入

    const num3 = 1.005;
    console.log(new Decimal(num3).toFixed(2).toString());

如果需要配置银行家舍入法,可以进行设置

Decimal.set({ rounding: 5 })
或是
const Decimal9 = Decimal.clone({ rounding: 5 })
b = new Decimal9(1)

配置表,默认是 1 ()

tion

away from zero

zero

-

.

If , away from zero

.

If , zero

.

If , even

.

If ,

.

If , -

Not a mode, see

但是小数点后面位数过多时,高精度库存储也会有问题,这个可能是 使用64位双精度,由0或1组成64位,有效数位数只有52位,有效数部分无法存储无限长度的二进制,后面的数据就会丢失,计算机只能存储一个近似的数字。

尽管 .js 旨在提供比原生 数字类型更高的精度,但它仍然受到底层浮点数系统的限制。

    const num3 = 1234567890.012345678;
    console.log(new Decimal(num3).toString()); // 1234567890.0123458