js 加减乘除精度

js小数点的计算精度会存在缺失问题,这里封装了一段代码用来解决加减乘除精度问题:

calc.js文件:

/**
 ** 加法函数,用来得到精确的加法结果
 ** 说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显。这个函数返回较为精确的加法结果。
 ** 调用:accAdd(arg1,arg2)
 ** 返回值:arg1加上arg2的精确结果
 **/
function accAdd(arg1, arg2) {
  let r1, r2, m
  try {
    r1 = arg1.toString().split('.')[1].length
  } catch (e) {
    r1 = 0
  }
  try {
    r2 = arg2.toString().split('.')[1].length
  } catch (e) {
    r2 = 0
  }
  m = Math.pow(10, Math.max(r1, r2))
  return (arg1 * m + arg2 * m) / m
}

/**
 ** 减法函数,用来得到精确的减法结果
 ** 说明:javascript的减法结果会有误差,在两个浮点数相减的时候会比较明显。这个函数返回较为精确的减法结果。
 ** 调用:accSub(arg1,arg2)
 ** 返回值:arg1加上arg2的精确结果
 **/
function accSub(arg1, arg2) {
  var r1, r2, m, n;
  try {
    r1 = arg1.toString().split(".")[1].length;
  } catch (e) {
    r1 = 0;
  }
  try {
    r2 = arg2.toString().split(".")[1].length;
  } catch (e) {
    r2 = 0;
  }
  m = Math.pow(10, Math.max(r1, r2)); //last modify by deeka //动态控制精度长度
  n = r1 >= r2 ? r1 : r2;
  return ((arg1 * m - arg2 * m) / m).toFixed(n);
}

/**
 ** 乘法函数,用来得到精确的乘法结果
 ** 说明:javascript的乘法结果会有误差,在两个浮点数相乘的时候会比较明显。这个函数返回较为精确的乘法结果。
 ** 调用:accMul(arg1,arg2)
 ** 返回值:arg1乘以 arg2的精确结果
 **/

function accMul(arg1, arg2) {
  let m = 0
  let s1 = arg1.toString()
  let s2 = arg2.toString()
  try {
    m += s1.split('.')[1] ? s1.split('.')[1].length : ''
  } catch (e) { }
  try {
    m += s2.split('.')[1] ? s2.split('.')[1].length : ''
  } catch (e) { }
  return (Number(s1.replace('.', '')) * Number(s2.replace('.', ''))) / Math.pow(10, m)
}

/**
 ** 除法函数,用来得到精确的除法结果
 ** 说明:javascript的除法结果会有误差,在两个浮点数相除的时候会比较明显。这个函数返回较为精确的除法结果。
 ** 调用:accDiv(arg1,arg2)
 ** 返回值:arg1除以arg2的精确结果
 **/
function accDiv(arg1, arg2) {
  let t1 = 0
  let t2 = 0
  let r1
  let r2
  try {
    t1 = arg1.toString().split('.')[1].length
  } catch (e) { }
  try {
    t2 = arg2.toString().split('.')[1].length
  } catch (e) { }
  r1 = Number(arg1.toString().replace('.', ''))
  r2 = Number(arg2.toString().replace('.', ''))
  return (r1 / r2) * Math.pow(10, t2 - t1)
}

// 封装
export const calcFn = {
  add() {
    // 创建一个新的,浅拷贝的数组实例
    const arg = Array.from(arguments)
    return arg.reduce((total, num) => {
      return accAdd(total, num)
    })
  },
  sub() {
    const arg = Array.from(arguments)
    return arg.reduce((total, num) => {
      return accSub(total, num)
    })
  },
  mul() {
    const arg = Array.from(arguments)
    return arg.reduce((total, num) => {
      return accMul(total, num)
    })
  },
  divide() {
    const arg = Array.from(arguments)
    return arg.reduce((total, num) => {
      return accDiv(total, num)
    })
  }
}

fn_handle.js调用:

import { calcFn } from './calc.js'

console.log(calcFn.add(1.1, 1.2, 1.3)) //加法调用

console.log(calcFn.sub(7.1, 1.2, 1.3, 2.5)) //减法调用

console.log(calcFn.mul(1.1, 1.2)) //乘法调用

console.log(calcFn.divide(75, 2.5, 1.2)) //除法调用

封装之后可以同时传入多个参数 ,不局限于只能两两计算

<think>好的,我现在需要解决用户关于JavaScript中加减乘除运算精度丢失的问题。用户提到的问题比如0.3*1=0.2999999999这样的错误,这可能是因为浮点数在二进制中的表示问题导致的。我需要根据提供的引用资料来整理解决方案。 首先,引用[3]提到可以将小数转换为整数进行计算,然后再调整回原来的倍数。例如,在加减乘除运算前,将小数乘以10的幂次方转换成整数,运算后再除以相应的倍数。这样可以避免浮点数的精度问题。例如,0.1 + 0.2可以转换为(1 + 2)/10 = 0.3。 引用[2]和[4]则提到了使用toFixed方法来保留指定位数的小数,但需要注意这可能并不总是可靠,因为toFixed本身也可能存在四舍五入的问题。比如,0.085.toFixed(2)可能会得到正确的结果,但如果是0.1.toFixed(20)可能会有多余的零。 另外,引用[1]和[3]都提到了处理乘除时需要特别处理倍数。例如,乘法需要将两个数的倍数相乘,而除法则需要调整倍数以确保精度。 接下来,我需要将这些方法具体化,给出加减乘除的函数实现。例如,加法函数需要确定两个数的小数位数,取较大的位数作为倍数,将两个数都转换为整数进行运算,最后再除以倍数。同样的,减法也需要类似的处理。 乘法和除法则需要更复杂的处理。乘法需要将两个数的倍数相乘,然后结果除以这个乘积的倍数。而除法则需要将被除数乘以倍数,然后除以除数,可能需要调整倍数来保持精度。 另外,用户可能需要一个四舍五入的函数,比如保留指定位数的小数,避免出现0.3000000004这样的情况。可以使用Math.round结合指数运算来实现。 最后,需要提醒用户注意输入必须为数字,避免NaN的情况,并且处理大数时可能的溢出问题。例如,使用指数法时,如果小数位数过多,可能会导致整数超出JavaScript的安全范围(2^53),从而引发新的精度问题。 总结步骤: 1. 转换为整数计算:加减乘除都先放大为整数,计算后再缩小。 2. 使用toFixed处理显示,但注意其局限性。 3. 实现具体的加减乘除函数,处理不同位数的小数。 4. 提供四舍五入的函数,确保结果精确到指定位数。 5. 注意事项:输入验证、溢出问题等。 现在需要将这些步骤整理成清晰的解决方案,并给出代码示例和相关问题。</think>### JavaScript中解决加减乘除精度丢失的方案 由于JavaScript使用IEEE 754标准的双精度浮点数表示小数,导致如$0.1 + 0.2 = 0.30000000000000004$的精度问题[^4]。以下是具体解决方案: --- #### 一、核心思路:整数化计算 将小数转换为整数进行运算,最后再调整倍数。例如: $$ \text{计算} \ 0.1 + 0.2 \ \Rightarrow \ (1 \times 10 + 2 \times 10) / 10 = 0.3 $$ 实现步骤如下: 1. **确定放大倍数**:根据小数位数计算$10^n$ 2. **转换为整数**:小数乘以倍数后取整 3. **数学运算**:对整数执行加减乘除 4. **缩小回原倍数**:结果除以对应倍数 --- #### 二、具体实现代码 ##### 1. 加法 ```javascript function add(a, b) { const maxDigits = Math.max( (a.toString().split('.')[1] || '').length, (b.toString().split('.')[1] || '').length ); const multiplier = 10 ** maxDigits; return (Math.round(a * multiplier) + Math.round(b * multiplier)) / multiplier; } ``` ##### 2. 减法 ```javascript function subtract(a, b) { return add(a, -b); // 复用加法逻辑 } ``` ##### 3. 乘法 ```javascript function multiply(a, b) { const aDigits = (a.toString().split('.')[1] || '').length; const bDigits = (b.toString().split('.')[1] || '').length; const multiplier = 10 ** (aDigits + bDigits); return (a * (10 ** aDigits)) * (b * (10 ** bDigits)) / multiplier; } ``` ##### 4. 除法 ```javascript function divide(a, b) { const aDigits = (a.toString().split('.')[1] || '').length; const bDigits = (b.toString().split('.')[1] || '').length; const multiplier = 10 ** (aDigits - bDigits); return (a * (10 ** aDigits)) / (b * (10 ** bDigits)) * multiplier; } ``` --- #### 三、辅助方法:精度截断 使用`toFixed`结合数值转换: ```javascript function round(value, digits) { return Number(Math.round(value + 'e' + digits) + 'e-' + digits); } console.log(round(0.1 + 0.2, 2)); // 输出0.3 ``` --- #### 四、注意事项 1. **输入验证**:确保参数为有效数字,避免`NaN` 2. **大数溢出**:放大后的整数不应超过$2^{53}$(JavaScript安全整数范围) 3. **性能优化**:频繁计算时建议使用第三方库如`decimal.js` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值