JavaScript Number 四舍五入并保留两位小数

Math.round()

JavaScript 提供了一个函数Math.round() 来做整数的四舍五入。

Math.round() 准确的定义是把参数转化为最接近的整数,如果与相邻两个整数距离相等那么返回较大的整数。在正数情况下符合日常理解的四舍五入的行为,在负数情况下更像是五舍六入。 例如, -0.5,距离相邻两个整数0, -1 距离一样,返回较大的整数 0。-0.6 距离-1更近,返回-1。

使用Math.round()先乘100再除100保留两位小数 ❌

Math.round() 只能处理整数,可以通过乘以100把小数点左移两位,然后再通过Math.round()完成整数的四舍五入,然后再把小数点右移两位(x1/100)。

看起来是好的,再多一点测试。

Number.EPSILON ❌

浮点计算会丢精度可以考虑加一点点数值来修正。加一个Number.EPSILON
Number.EPSILON是一个常量值,最小的大于1的浮点数和1的差。

Chrome下 Number.EPSILON
=2.220446049250313e-16

再多一点测试

没的救了,换个其他方法

toFixed ❌

toFixed 参数是小数点后保留几位小数,返回的是string。参数默认为0。

一模一样的失败,还有个toPrecision 跟 toFixed 一样的失败。

toPrecision ❌

toPrecision 参数一共有几位有效数字,包括整数和小数位。如果没填参数,就等同于Number.prototype.toString()

toPrecision & round

浮点数在计算时会丢失精度,可以通过JavaScript有效数字位数是17, 可以通过降低精度toPrecision(15)完成精度的修正。差不多算是错错之后看起来为正。

Exponential notation

任何一个实数都可以写成 x * 10^y 的形式,用指数表示法就是 xEy, eE 在浮点数字中代表指数。

通过指数表示法,避免对浮点数做计算的方式来调整小数点位置,防止精度损失放大,然后配合round完成四舍五入。

lodash

Lodash的round实现原理类似。
_.round(number, [precision = 0])

为什么一个简单的四舍五入并保留两位小数这么麻烦

0.1 在浮点数里并不存在

当我们声明一个小数时,比如0.1其实它并不是0.1它其实是0.10000000000000000555111512312578270211815834045410。编程语言在默认打印的时候会降低精度再打印,让他看起来是0.1

这样就能看出为什么保留两位小数有时候好使,有时候就不好使。

浮点的标识方式

浮点数是采用科学计数法来表示一个数字的,常见的编程语言的浮点数都是基于IEEE754标准。 IEEE754 浮点数基数固定是2,所以还需要关注符号、尾数和指数三部分。
sign 符号, 表示正负号
exponent 指数,表示次方数
mantissa 尾数,表示精确度
$(-1)^s2^e1.mantissa$

由于基数是2,也就无法表达出我们常见的小数,例如: 0.1, 0.2, 0.05。对于无法表达的数只能使用近似值,也就导致 0.1 + 0.2 = 0.30000000000000004。
只要是浮点表示的小数,早晚会遇到精度问题。
对于需要精准小数计算的还是要用Math.jsdecimal.js这种专门的库来计算。

更多浮点相关的知识

15 张图带你深入理解浮点数
IEEE-754浮点数对应二进制转化
IEEE-754浮点数可视化
IEEE-754浮点数可视化float-toy

评论关闭。