js减法处理精度丢失

1,278 阅读1分钟
实现思路
  1. 将减数和被减数扩大n倍,然后相减,最后结果再缩小n倍。
  2. 使用字符串,补全减数和被减数小数点后面的小数(根据最长的一个值补全)。
  3. 去掉小数点,转为整数;计算;在之前小数位置添加上小数点。
  4. 处理一下正负数 。
  5. js, number 类型使用 IEEE 754 格式表示整数和浮点值。注意这里放大后的数要在 2^53 内。
代码实现(方法一)
function fn(a, b) {
    // 是否正数
    let positiveNumber = true;
    if(a<b){
        [a,b] = [b,a];
        positiveNumber = false;
    }
    let aStr = a.toString();
    let bStr = b.toString();
    let aArr = aStr.split('.');
    let bArr = bStr.split('.');
    let aLen = aArr[1]?aArr[1].length : 0;
    let bLen = bArr[1]?bArr[1].length : 0;
    // 获取最后的小数位数
    let maxLen = Math.max(aLen, bLen);
    aStr = parseFloat(aStr).toFixed(maxLen);
    bStr = parseFloat(bStr).toFixed(maxLen);

    aStr = aStr.split('.').join('');
    bStr = bStr.split('.').join('');

    let result = parseFloat(aStr) - parseFloat(bStr);

    // 从尾巴往前 maxLen 位置就是小数点插入位置
    result = result.toString().split('').reverse().join('');
    // 少于小数点长度需要补全
    result = result.padEnd(maxLen + 1, '0');
    result = result.split('');
    result.splice(maxLen, 0, '.');
    result = result.reverse().join('');

    if(!positiveNumber){
        result = '-' + result;
    }
    return result;
}
代码实现(方法二)思路和一同,简化版
function fn(a, b) {
    let aDecimalLen, // a 小数长度
        bDecimalLen, // b 小数长度
        maxLen, // 最长的小数长度
        multiple; // 扩大的倍数

    try{
        aDecimalLen = a.toString().split('.').length;
    }catch (e) {
        aDecimalLen = 0;
    }
    try{
        bDecimalLen = b.toString().split('.').length;
    }catch (e) {
        bDecimalLen = 0;
    }
    maxLen = Math.max(aDecimalLen, bDecimalLen);
    multiple = Math.pow(10, maxLen);
    return ((a * multiple - b * multiple) / multiple).toFixed(maxLen);
}

验证

let a = 0.02;
let b = 0.01;
console.log(fn(a, b)); 
console.log(a - b);