当前位置: 首页 > news >正文

解决前端计算的浮点精度问题

问题:比如1001*1.11等于110.11

但是如果用前端开发处理的话 ,因为涉及到浮点数运算(这是因为JavaScript(以及其他许多编程语言)使用IEEE 754标准来表示浮点数,导致某些十进制小数无法精确表示,从而产生精度误差),导致1001*1.11等于110.1100000000001

解决方案:

1.使用整数进行计算

将浮点数转换为整数进行计算,最后再转换回浮点数。例如,将金额以“分”为单位进行计算,而不是以“元”为单位

let a = 0.1;
let b = 0.2;
let result = (a * 10 + b * 10) / 10; // 0.3

2.使用 toFixed 方法

toFixed 方法可以将数字四舍五入到指定的小数位数,返回一个字符串。但要注意,toFixed 返回的是字符串,可能需要转换为数字。

let a = 0.1;
let b = 0.2;
let result = parseFloat((a + b).toFixed(1)); // 0.3

3.使用第三方库

有一些专门处理高精度计算的库,如 decimal.jsbig.js 或 math.js,它们提供了更精确的数值计算功能。

// 使用 decimal.js
let a = BigInt(12345678901234567890);
let b = BigInt(98765432109876543210);
let result = a + b; // 111111111011111111100n

对比:

4. 避免直接比较浮点数

在比较浮点数时,尽量避免使用 == 或 ===,而是使用一个很小的误差范围(epsilon)来判断是否相等。

function areEqual(a, b, epsilon = 0.00001) {
    return Math.abs(a - b) < epsilon;
}

let a = 0.1 + 0.2;
let b = 0.3;
console.log(areEqual(a, b)); // true
 

5.使用 Math 函数

对于某些特定场景,可以使用 Math 函数来处理精度问题,例如 Math.roundMath.floorMath.ceil 等。

let a = 0.1 + 0.2;
let result = Math.round(a * 10) / 10; // 0.3

6.使用 BigIn

如果涉及大整数计算,可以使用 BigInt 类型,它可以精确表示任意大小的整数。

let a = BigInt(12345678901234567890);
let b = BigInt(98765432109876543210);
let result = a + b; // 111111111011111111100n

我目前使用的是用第三方库decimal.js的方案

1.安装

npm install decimal.js

2.封装一个js的方法

// 处理数据相乘的浮点精度问题

export function calculateProduct(num1, num2) {

   num1=Number(num1)

   num2=Number(num2)

  const result = new Decimal(num1).times(new Decimal(num2));

  return result.toNumber() || 0;

}

3.使用

  let num=calculateProduct(row.PriceExclTax,row.ShortQuantity)

4.方法

  • 使用 .plus() 进行加法。

  • 使用 .minus() 进行减法。

  • 使用 .times() 进行乘法。

  • 使用 .dividedBy() 进行除法。

  • 支持链式调用,代码简洁。

  • 通过 Decimal.set 配置全局精度和舍入模式。

4.1  加法(Addition)

import { Decimal } from 'decimal.js';

let a = new Decimal(0.1);
let b = new Decimal(0.2);
let sum = a.plus(b); // 0.3
console.log(sum.toString()); // "0.3"

4.2  减法(Subtraction)

import { Decimal } from 'decimal.js';

let a = new Decimal(0.3);
let b = new Decimal(0.1);
let difference = a.minus(b); // 0.2
console.log(difference.toString()); // "0.2"

4.3   乘法(Multiplication)

import { Decimal } from 'decimal.js';

let a = new Decimal(0.1);
let b = new Decimal(0.2);
let product = a.times(b); // 0.02
console.log(product.toString()); // "0.02"

4.4   除法(Division)

使用 .dividedBy() 方法。

import { Decimal } from 'decimal.js';

let a = new Decimal(10);
let b = new Decimal(3);
let quotient = a.dividedBy(b); // 3.333333333
console.log(quotient.toString()); // "3.333333333"

4.5  链式调用

decimal.js 支持链式调用,可以在一行代码中完成多个运算。

import { Decimal } from 'decimal.js';

let result = new Decimal(10)
    .dividedBy(3) // 10 / 3
    .plus(1)      // + 1
    .times(2)     // * 2
    .toFixed(2);  // 保留两位小数
console.log(result); // "8.67"

4.6  处理浮点数精度问题

decimal.js 的核心优势是解决 JavaScript 原生浮点数计算的精度问题。

import { Decimal } from 'decimal.js';

// 原生 JavaScript 的精度问题
let nativeResult = 0.1 + 0.2; // 0.30000000000000004

// 使用 decimal.js 解决精度问题
let decimalResult = new Decimal(0.1).plus(0.2); // 0.3
console.log(decimalResult.toString()); // "0.3"

4.7  格式化输出

可以使用 .toFixed() 或 .toString() 方法格式化结果。

import { Decimal } from 'decimal.js';

let result = new Decimal(10).dividedBy(3); // 3.333333333
console.log(result.toFixed(2)); // "3.33"
console.log(result.toString()); // "3.333333333"

4.8  全局配置

可以通过 Decimal.set 方法全局配置精度和舍入模式

import { Decimal } from 'decimal.js';

// 设置全局精度为 10,舍入模式为四舍五入
Decimal.set({ precision: 10, rounding: Decimal.ROUND_HALF_UP });

let result = new Decimal(10).dividedBy(3); // 3.333333333
console.log(result.toFixed(2)); // "3.33"

4.9   完整示例

import { Decimal } from 'decimal.js';

// 设置全局配置
Decimal.set({ precision: 10, rounding: Decimal.ROUND_HALF_UP });

// 加法
let sum = new Decimal(0.1).plus(0.2); // 0.3

// 减法
let difference = new Decimal(0.3).minus(0.1); // 0.2

// 乘法
let product = new Decimal(0.1).times(0.2); // 0.02

// 除法
let quotient = new Decimal(10).dividedBy(3); // 3.333333333

// 链式调用
let result = new Decimal(10)
    .dividedBy(3)
    .plus(1)
    .times(2)
    .toFixed(2); // "8.67"

console.log({ sum, difference, product, quotient, result });

相关文章:

  • lowagie(itext)老版本手绘PDF,包含页码、水印、图片、复选框、复杂行列合并、行高设置等。
  • express(node ORM) 使用 Winston 记录日志 及数据库保存日志
  • DeepSeek在金融银行的应用方案
  • Unity基础——资源导出分享为Unity Package
  • 腾讯 DeepSeek-R1 × Vue3 使用体验报告
  • 深入浅出Spring Boot框架:从入门到精通
  • MySQL——创建与管理视图
  • ffmpeg-rockchip RK3588 armbian小盒子上编译rk硬件加速
  • 计算机毕业设计 ——jspssm510springboot 的人职匹配推荐系统
  • Linux下原子操作`__atomic_store_n`和`__atomic_load_n`的消耗问题
  • liunx安装redis并配置主从
  • ffmpeg常用方法(一)
  • 【MySQL】Mysql超大分页处理
  • 02_linux系统命令
  • 蓝桥杯备赛-拔河
  • 当下弹幕互动游戏源码开发教程及功能逻辑分析
  • excel
  • 网络渗透作业
  • 本地大模型编程实战(24)用智能体(Agent)实现智能纠错的SQL数据库问答系统(3)
  • 面试葵花宝典之React(持续更新中)
  • 绿植租摆网站建设/如何制作自己的链接
  • ps网页素材/百度seo排名优
  • 建设一个企业网站/吴中seo页面优化推广
  • 防城港网站建设/2023年最新新闻简短摘抄
  • 中英文网站如何做思路/app排名优化
  • 如何判断一个网站是恶意网站/武汉百度信息流广告