js小数运算出现的问题(精度丢失)及解决办法-亲测有效

简介: JavaScript浮点数运算存在精度丢失问题,如0.1+0.2不等于0.3。原因是十进制小数转二进制时可能出现无限循环,导致舍入误差。本文提供一种精度处理方法,通过将小数转为整数运算后再还原,实现加减乘除的精确计算,解决常见浮点运算误差问题。

在项目中出现的问题

加法
0.1+0.2 = 0.30000000000000004
减法
1-0.8 = 0.19999999999999996
乘法
0.6*0.75 = 0.44999999999999996
9.2*100 = 919.9999999999999
除法
1.2/0.2 = 5.999999999999999

出现问题的大致原因是 Number类型运算都需要先将十进制转二进制,但小数点后的位数转二进制会出现无限循环的问题,只能舍0入1,所以会出现小数点丢失问题。
感兴趣的可以自己研究,在这里只是简单阐述下。

解决办法

/**
 * 小数精确度处理
 * @param {number} num1 数字
 * @param {number} num2 数字
 * @param {string} symbol +-*\/符号
 */
function amendNumber(num1, num2, symbol) {
   
  let result
  let str1Length = 0
  let str2Length = 0

  // 解决整数没有小数点方法
  try {
   
    str1Length = (num1 + '').split('.')[1].length
  } catch (e) {
   
    //
  }
  try {
   
    str2Length = (num2 + '').split('.')[1].length
  } catch (error) {
   
    //
  }
  const step = Math.pow(10, Math.max(str1Length, str2Length))
  const n1 = Number((num1 * step).toFixed()) // 转换成整数 0.0012 * 100000000 = 119999.99999999999
  const n2 = Number((num2 * step).toFixed()) // 转换成整数 0.0012 * 100000000 = 119999.99999999999
  switch (symbol) {
   
    case '+':
      result = (n1 + n2) / step
      break
    case '-':
      result = (n1 - n2) / step
      break
    case '*':
      result = (n1 * n2) / (step * step)
      break
    case '/':
      result = n1 / n2
      break
    default:
      break
  }
  return result
}

/**
 * 加法
 * @param {number} num1
 * @param {number} num2
 * @returns
 */
function add(num1, num2) {
   
  return amendNumber(num1, num2, '+')
}

/**
 * 减法
 * @param {number} num1
 * @param {number} num2
 * @returns
 */
function subtract(num1, num2) {
   
  return amendNumber(num1, num2, '-')
}

/**
 * 乘法
 * @param {number} num1
 * @param {number} num2
 * @returns
 */
function multiply(num1, num2) {
   
  return amendNumber(num1, num2, '*')
}

/**
 * 除法
 * @param {number} num1
 * @param {number} num2
 * @param {number} fractionDigits 精确小数几位
 * @returns
 */
function divide(num1, num2, fractionDigits) {
   
  const value = amendNumber(num1, num2, '/')
  if (!isNaN(fractionDigits) && typeof fractionDigits === 'number') {
   
    return value.toFixed(fractionDigits) - 0
  } else {
   
    return value
  }
}

//测试
console.log('加法:', add('a', 0.2)) // NaN
console.log('加法:', add(NaN, 0.2)) // NaN
console.log('加法:', add('0.1', 0.2)) // 0.3
console.log('减法:', subtract(1, 0.8)) // 0.2
console.log('乘法:', multiply(0.6, 0.75)) // 0.45
console.log('乘法:', multiply(9.2, 100)) // 920
console.log('除法:', divide(1.2, 0.2)) // 6
console.log('除法:', divide(1, 3)) // 0.3333333333333333
console.log('除法:', divide(1, 3, 3)) // 0.333
目录
相关文章
|
12月前
|
JavaScript 前端开发
JS浮点数精度问题及高精度小数运算:BigNumber解决方案
JS浮点数精度问题及高精度小数运算:BigNumber解决方案
1165 0
|
JavaScript
js 保留2位小数
js 保留2位小数
250 124
|
JavaScript 前端开发
今天被JavaScript的String型和数字型的+运算撞了一下腰。
今天被JavaScript的String型和数字型的+运算撞了一下腰。
|
JavaScript 前端开发 Java
JavaScript小数四舍五入的代码
JavaScript小数四舍五入的代码
115 8
|
存储 JavaScript 前端开发
js的变量以及运算
js的变量以及运算
75 1
|
JavaScript
必知的技术知识:js保留二位小数
必知的技术知识:js保留二位小数
922 0
|
小程序 开发工具 开发者
【微信小程序】微信开发者工具 引用 vant-weapp时“miniprogram/node_modules/@babel/runtime/index.js: 未找到npm包入口文件” 解决办法
【微信小程序】微信开发者工具 引用 vant-weapp时“miniprogram/node_modules/@babel/runtime/index.js: 未找到npm包入口文件” 解决办法
1068 1
|
前端开发 JavaScript
前端 JS 经典:双等号运算符的运算和转换规则
前端 JS 经典:双等号运算符的运算和转换规则
134 0
|
JavaScript 前端开发 数据处理
掌握JavaScript中的二进制运算,提升你的编程技能!
掌握JavaScript中的二进制运算,提升你的编程技能!
|
JavaScript
js 强制保留2位小数
js 强制保留2位小数
157 0