JS直接乘100除以100 没有四舍五入 精度丢失问题

847 阅读3分钟

前言:

看到掘金贴子

 function formatNum(num) {
            //1. 可能是字符串,转换为浮点数
            //2. 乘以100 小数点向右移动两位
            //3. Math.round 进行四舍五入
            //4. 除以100 小数点向左移动两位 实现保留小数点后两位
            var value = Math.round(parseFloat(num) * 100) / 100;
            // var value = Math.round(num * Math.pow(10, 2)) / Math.pow(10, 2);

            console.log('value', value)
            // 去掉小数点 存为数组
            var arrayNum = value.toString().split(".");
            //只有一位(整数)
            if (arrayNum.length == 1) {
                // return arrayNum[0] + ".00";  
                return value.toString() + ".00";
            }
            if (arrayNum.length > 1) {
                //小数点右侧 如果小于两位 则补一个0
                if (arrayNum[1].length < 2) {
                    return value.toString() + "0";
                }
                return value;
            }

        }
        console.log('parseFloat(1015.5)', parseFloat(1015.5)); // 10.15
        console.log('Math.round(1015.5)', Math.round(1015.5)); //1016
        console.log('Math.round(parseFloat(num) * 100)', Math.round(parseFloat(10.155) * 100))

在这里插入图片描述 应输出 "10.16" 但是结果是 10.15

另一个写法

		//四舍五入方法,保留小数方法
        //data:需要处理的数据  size:需要保留几位小数
        function fourFive(data,size) {
            let a = Math.pow(10,size)
            //最终四舍五入得出的结果
            let result =  Math.round(data * a) / a
            //保留小数位操作
            let b = result.toString().split(".")
            if(b.length>1){
                let c = b[1].toString().split("").length
                if(c == size ){
                    return result
                }else{
                    return result.toFixed(size)
                }
            }else{
                return result.toFixed(size)
            }
        }

结果同样是10.15

解决:

 value = +(Math.round(num + "e+2") + "e-2")

这段JavaScript代码使用了一种巧妙的方式来处理浮点数的四舍五入问题,尤其是当你想要四舍五入到特定的小数位数时。代码的核心思想是利用科学记数法(即使用“e”表示的指数形式)来先放大数字,进行四舍五入,然后再缩小回去。下面是对这一过程的详细解释:

  1. num + "e+2": 这一部分将数字num转换成字符串,并加上"e+2",表示将num乘以10^2(即100)。这样做的目的是将num中需要四舍五入的小数部分移到整数位,以便进行精确的四舍五入操作。例如,如果num10.155,这一步会将其转换成"1015.5e+2",然后因为是数值和字符串的连接,所以实际上是"10.155e+2"

  2. Math.round(...): 接下来,Math.round函数对上一步得到的字符串表示的数值进行四舍五入。由于步骤1中已经通过指数形式放大了数值,这里的四舍五入操作能够正确地应用到原始数值的小数部分。继续上面的例子,四舍五入操作应用于1015.5,结果是1016

  3. ... + "e-2": 四舍五入后的结果再次被转换成字符串,并加上"e-2",这表示将数值除以10^2。这一步是为了将步骤1中放大的数值缩小回原来的大小。以1016为例,加上"e-2"后,字符串变为"1016e-2"

  4. +(...): 最外层的加号是一元加法操作符,它将字符串强制转换回数值类型。所以,"1016e-2"会被转换成10.16

综上所述,这段代码通过使用科学记数法来先放大数值进行四舍五入,然后再缩小,从而实现了对浮点数进行精确四舍五入到指定小数位的操作。这种方法有效地规避了直接四舍五入浮点数时可能遇到的精度问题。

代码

方法一

不好的点是:只有一位小数或者整数的时候返回的是string类型

function formatNum(num) {
            var value = +(Math.round(num + "e+2") + "e-2")
            var arrayNum = value.toString().split(".");)
            if (arrayNum.length == 1) { 
                return value.toString() + ".00";
            }
            if (arrayNum.length > 1) {
                if (arrayNum[1].length < 2) {
                    return value.toString() + "0";
                }
                return value;
            }
        }

在这里插入图片描述

方法二

  function fourFive(data, size) {
            //最终四舍五入得出的结果
            let result = +(Math.round(data + `e+${size}`) + `e-${size}`)
            //保留小数位操作
            let b = result.toString().split(".")
            if (b.length > 1) {
                let c = b[1].toString().split("").length
                if (c == size) {
                    return result
                } else {
                    return result.toFixed(size)
                }
            } else {
                return result.toFixed(size)
            }
        }

插件:

现成的库

decimal