一、toFixed和 Math.round四舍五入

1. toFixed()方法

toFixed() 方法可把 Number 四舍五入为指定小数位数的数字,但其四舍五入的规则与数学中的规则不同,使用的是银行家舍入规则,银行家舍入:所谓银行家舍入法,其实质是一种四舍六入五取偶(又称四舍六入五留双)法。具体规则如下:四舍六入五考虑,五后非零就进一,五后为零看奇偶,五前为偶应舍去,五前为奇要进一。

1.55.toFixed(1)      //1.6
1.555.toFixed(2)    //1.55

2. Math.round()

Math.round() 函数返回一个数字四舍五入后最接近的整数。
如果参数的小数部分大于 0.5,则舍入到相邻的绝对值更大的整数。 如果参数的小数部分小于 0.5,则舍入到相邻的绝对值更小的整数。如果参数的小数部分恰好等于0.5,则舍入到相邻的在正无穷(+∞)方向上的整数。Math.round()并不总是舍入到远离0的方向(尤其是在负数的小数部分恰好等于0.5的情况下)

Math.round(30.49)   //30
Math.round(30.5)    //31
Math.round(-30.49);   //-30
Math.round(-30.5);   //-30
Math.round(-30.51);  //-31

3. Math.pow(base, exponent)

返回基数(base)的指数(exponent)次幂

Math.pow(4, 0.5)   //2
 Math.pow(4, 2)    //16

4. parseFloat()

函数可解析一个字符串,并返回一个浮点数

parseFloat("9")       //9
parseFloat("44 12 33")    //44
parseFloat("30 aaaa")   //30
parseFloat("word 30")   //NaN

二、数字按指定精度四舍五入最终方法

思路:数字(number)乘以10的精度(precision)次幂,再除以10的精度(precision)次幂

function round(number, precision) {
  return parseFloat(
    Math.round(Number(number) * Math.pow(10, precision)) /
      Math.pow(10, precision)
  );
}

round(1.555, 2); //1.56

三、js中数字直接计算bug

1、原生js运算结果不一定准确,会丢失精度

console.log(0.1 + 0.2);        //0.30000000000000004
console.log(1.99 - 0.9);       //1.0899999999999999
console.log(7 * 0.7);          //4.8999999999999995
console.log(5.99 / 1000);      //0.0059900000000000005

2、原因
数字转换为二进制的过程中丢失了精度

3、解决方案
计算前乘以10的n次方幂,计算后再除以10的n次方幂

四、修复JS中浮点数加减乘除小数点异常bug

1、加法

扩大小数点位数最多的倍数,add方法中使用了修复的乘法计算

function accAdd(a, b) {
    var c, d, e;
    try {
        c = a.toString().split(".")[1].length;
    } catch (f) {
        c = 0;
    }
    try {
        d = b.toString().split(".")[1].length;
    } catch (f) {
        d = 0;
    }
    return e = Math.pow(10, Math.max(c, d)), (accMul(a, e) + accMul(b, e)) / e;
}

//给Number类型增加一个add方法

Number.prototype.add = function (arg) {
    return accAdd(arg, this);
};
Number(1.111).add(2.123);   // 3.234

2、减法

accSub方法中使用了修复的乘法计算

function accSub(a, b) {
    var c, d, e;
    try {
        c = a.toString().split(".")[1].length;
    } catch (f) {
        c = 0;
    }
    try {
        d = b.toString().split(".")[1].length;
    } catch (f) {
        d = 0;
    }
    return e = Math.pow(10, Math.max(c, d)), (accMul(a, e) - accMul(b, e)) / e;
}
Number.prototype.sub= function (arg){ 
  return accSub(arg,this); 
}

3、乘法

function accMul(a, b) {
    var c = 0,
        d = a.toString(),
        e = b.toString();
    try {
        c += d.split(".")[1].length;
    } catch (f) {}
    try {
        c += e.split(".")[1].length;
    } catch (f) {}
    return Number(d.replace(".", "")) * Number(e.replace(".", "")) / Math.pow(10, c);
}

// 给Number类型增加一个mul方法,调用起来更加方便。

Number.prototype.mul = function (arg) {
    return accMul(arg, this);
};
Number(1.234).mul(2.1);     // 2.5914

4、除法

function accDiv(a, b) {
    var c, d, e = 0,
        f = 0;
    try {
        e = a.toString().split(".")[1].length;
    } catch (g) {}
    try {
        f = b.toString().split(".")[1].length;
    } catch (g) {}
    return c = Number(a.toString().replace(".", "")), d = Number(b.toString().replace(".", "")), accMul(c / d, Math.pow(10, f - e));
}

//给Number类型增加一个div方法,调用起来更加方便。

Number.prototype.div = function (arg) {
    return accDiv(this, arg);
};
Number(2.2).div(1.1)    //2

五、js计算插件

Math.js
Numeral.js