JavaScript 金额运算精度丢失问题及解决方案

news2025/3/20 12:04:57

JavaScript 金额运算精度丢失问题及解决方案

    • 1. 前言
    • 2. 为什么 JavaScript 计算金额会精度丢失?
      • 2.1 JavaScript 使用 IEEE 754 双精度浮点数
      • 2.2 浮点运算错误示例
        • **错误示例 1:0.1 + 0.2 ≠ 0.3**
        • **错误示例 2:浮点乘法精度问题**
    • 3. 解决方案
      • **方案 1:使用整数运算(推荐)**
      • **方案 2:使用 `toFixed()`(简单但不推荐)**
      • **方案 3:使用 `Number.EPSILON` 进行误差修正**
      • **方案 4:使用 BigDecimal 类库(最佳方案)**
      • **方案 5:使用 ES11 `BigInt`(适用于整数金额计算)**
    • 4. 结论
    • 5. 总结

1. 前言

在 JavaScript 中,浮点数运算可能会产生精度丢失的问题,尤其在处理 金额计算 时,这可能会导致严重的业务逻辑错误。例如:

console.log(0.1 + 0.2); // 0.30000000000000004
console.log(0.07 * 100); // 7.000000000000001
console.log(0.1 + 0.7 === 0.8); // false

这些问题主要是由于 JavaScript 使用 IEEE 754 双精度浮点数(64 位)来表示数字,某些小数无法用二进制精确表示,从而导致精度丢失。

本篇文章将深入剖析 JavaScript 金额计算精度丢失的原因,并提供多种 解决方案 来避免这些问题。


2. 为什么 JavaScript 计算金额会精度丢失?

2.1 JavaScript 使用 IEEE 754 双精度浮点数

JavaScript 所有的 Number 类型 都遵循 IEEE 754 双精度浮点数(64 位)标准,它的存储方式如下:

符号位指数位尾数位(小数部分)
1 位11 位52 位

某些十进制小数无法用二进制精确表示,类似于 1/3 在十进制中是无限循环小数 0.3333...,而 0.1二进制 下也会变成 无限循环小数

0.1(十进制) = 0.000110011001100110011...(二进制 无限循环)

由于存储空间限制,JavaScript 只能截取前 52 位,导致数值被四舍五入,最终引发计算误差。


2.2 浮点运算错误示例

错误示例 1:0.1 + 0.2 ≠ 0.3
console.log(0.1 + 0.2); // 0.30000000000000004

解析

  1. 0.1 的二进制近似值:0.00011001100110011...
  2. 0.2 的二进制近似值:0.0011001100110011...
  3. 计算后,得到的二进制不是 精确的 0.3,而是 0.30000000000000004

错误示例 2:浮点乘法精度问题
console.log(0.07 * 100); // 7.000000000000001

0.07 转换成二进制后是 0.000100011110101110000101...,乘以 100 后的结果并不完全等于 7


3. 解决方案

方案 1:使用整数运算(推荐)

核心思想
避免小数计算,将小数转换为整数计算,计算完成后再转回小数。

function add(a, b) {
    return (a * 100 + b * 100) / 100;
}

console.log(add(0.1, 0.2)); // 0.3
console.log(add(0.07, 0.02)); // 0.09

适用场景

  • 适用于 加法、减法、乘法、除法 计算。
  • 适用于 金额计算,例如:分(整数)代替元(小数)。

方案 2:使用 toFixed()(简单但不推荐)

console.log((0.1 + 0.2).toFixed(2)); // "0.30"
console.log((0.07 * 100).toFixed(2)); // "7.00"

缺点

  • toFixed() 返回的是 字符串,如果要继续计算,还需转换回 Number 类型:
    let result = Number((0.1 + 0.2).toFixed(2)); // 0.3
    
  • 不能完全解决浮点运算的问题,只适用于 结果展示

方案 3:使用 Number.EPSILON 进行误差修正

原理
Number.EPSILON 是 JavaScript 最小的精度差值(约 2.22e-16),可用于修正浮点计算误差:

function add(a, b) {
    return Math.round((a + b + Number.EPSILON) * 100) / 100;
}

console.log(add(0.1, 0.2)); // 0.3
console.log(add(0.07, 0.02)); // 0.09

适用场景

  • 用于 浮点数精度修正,避免直接使用 toFixed()

方案 4:使用 BigDecimal 类库(最佳方案)

JavaScript 原生 Number 无法解决所有精度问题,因此可以使用 BigDecimal 第三方库 来进行精准计算,例如 decimal.js

安装:

npm install decimal.js

使用:

const Decimal = require('decimal.js');

console.log(new Decimal(0.1).plus(0.2).toNumber()); // 0.3
console.log(new Decimal(0.07).times(100).toNumber()); // 7

优点

  • 可以处理 任意精度 运算,特别适用于 金融计算

方案 5:使用 ES11 BigInt(适用于整数金额计算)

BigInt 可用于 大数计算,但 不支持小数

const a = BigInt(100); // 1.00 元
const b = BigInt(200); // 2.00 元

console.log((a + b) / BigInt(100)); // 3n (表示 3 元)

适用场景

  • 仅适用于 整数计算(如分单位),不适用于 小数计算

4. 结论

方案适用场景优点缺点
整数运算(推荐)金额计算高效、适用范围广需要手动转换
toFixed()仅限展示简单易用结果为字符串,无法继续计算
Number.EPSILON浮点修正适用于加减运算不适用于复杂运算
decimal.js(最佳)任何精度计算高精度,API 强大需引入库
BigInt整数计算适用于大数运算不支持小数

5. 总结

JavaScript 的浮点运算容易导致金额计算误差,我们可以通过 整数运算、Number.EPSILON、BigDecimal 库等方式 来解决。

如果你正在开发电商、金融、结算系统推荐使用 decimal.js 或整数运算,以保证计算精度。

你还遇到过 JavaScript 金额计算的问题吗?欢迎留言讨论!🚀

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2318357.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java SE 面经

1、Java 语言有哪些特点 Java 语言的特点有: ①、面向对象。主要是:封装,继承,多态。 ②、平台无关性。一次编写,到处运行,因此采用 Java 语言编写的程序具有很好的可移植性。 ③、支持多线程。C 语言没…

关于redis中的分布式锁

目录 分布式锁的基础实现 引入过期时间 引入校验id 引入lua脚本 引入看门狗 redlock算法 分布式锁的基础实现 多个线程并发执行的时候,执行的先后顺序是不确定的,需要保证程序在任意执行顺序下,执行逻辑都是ok的。 在分布式系统中&am…

Python实战(2)-数据库支持

使用简单的纯文本文件可实现的功能有限。诚然,使用它们可做很多事情,但有时可能还需要额外的功能。你可能希望能够自动完成序列化,此时可求助于shelve和pickle(类似于shelve)​。不过你可能需要比这更强大的功能。例如…

从 Snowflake 到 Databend Cloud:全球游戏平台借助 Databend 实现实时数据处理

导读:某全球游戏平台为全球数百万玩家提供实时的技能型游戏体验与无缝的实时互动。对该游戏平台而言,保持数据的实时更新和实时分析,对提升玩家互动和留存率至关重要。他们在使用 Snowflake 进行实时数据摄取和分析时遇到了重大挑战&#xff…

Docker搭建MySQL主从服务器

一、在主机上创建MySQL配置文件——my.cnf master服务器配置文件路径:/data/docker/containers/mysql-cluster-master/conf.d/my.cnf slave服务器配置文件路径: /data/docker/containers/mysql-cluster-master/conf.d/my.cnf master服务配置文件内容 …

C语言每日一练——day_12(最后一天)

引言 针对初学者,每日练习几个题,快速上手C语言。第十二天。(最后一天,完结散花啦) 采用在线OJ的形式 什么是在线OJ? 在线判题系统(英语:Online Judge,缩写OJ&#xff0…

10、STL中的unordered_map使用方法

一、了解 1、unordered_map(哈希) unordered_map是借用哈希表实现的关联容器。 访问键值对O(1),最坏情况O(n),例如哈希冲突严重时。【n是一个哈希桶的元素数量】 unordered_map特性 键值对存储&#xff…

本地部署deepseek-r1建立向量知识库和知识库检索实践【代码】

目录 一、本地部署DS 二、建立本地知识库 1.安装python和必要的库 2.设置主目录工作区 3.编写文档解析脚本 4.构建向量数据库 三、基于DS,使用本地知识库检索 本地部署DS,其实非常简单,我写了一篇操作记录,我终于本地部署了DeepSeek-R1(图文全过程)-CSDN博客 安装…

监控视频联网平台在智慧水利中的应用

随着智慧城市建设的深入推进,智慧水利作为其中的重要组成部分,正逐步实现数字化、智能化和网络化转型。在这一过程中,监控视频联网平台凭借其高效的数据采集、传输与分析能力,成为智慧水利建设的关键技术支撑。以下是监控视频联网…

深入解析素数筛法:从埃氏筛到欧拉筛的算法思想与实现

素数筛法是一种用于高效生成素数的算法。常见的素数筛法包括埃拉托斯特尼筛法(埃氏筛)和欧拉筛(线性筛)。下面我们将详细讲解这两种筛法的思想: 一、 埃拉托斯特尼筛法(埃氏筛) 思想&#xff1…

ubuntu20.04系统没有WiFi图标解决方案_安装Intel网卡驱动

文章目录 1. wifi网卡配置1.1 安装intel官方网卡驱动backport1.1.1 第四步可能会出现问题 1.2 ubuntu官方的驱动1.3 重启 1. wifi网卡配置 我的电脑是华硕天选4(i7,4060),网卡型号intel ax201 ax211 ax210通用。 参考文章&#…

网络编程---多客户端服务器

写一个服务器和两个客户端 运行服务器和2个客户端,实现聊天功能 客户端1 和 客户端2 进行聊天 客户端1将聊天数据发送给服务器 服务器将聊天数据转发给客户端2 要求: 服务器使用 select 模型实现 客户端1使用 poll 模型实现 客户端2使用 多线程实现…

LeetCode 2614.对角线上的质数:遍历(质数判断)

【LetMeFly】2614.对角线上的质数:遍历(质数判断) 力扣题目链接:https://leetcode.cn/problems/prime-in-diagonal/ 给你一个下标从 0 开始的二维整数数组 nums 。 返回位于 nums 至少一条 对角线 上的最大 质数 。如果任一对角线上均不存在质数&…

红日靶场(二)——个人笔记

靶场搭建 新增VMnet2网卡 **web:**需要配置两张网卡,分别是外网出访NAT模式和内网域环境仅主机模式下的VMnet2网卡。 **PC:**跟web一样,也是需要配置两张网卡,分别是外网出访NAT模式和内网域环境仅主机模式下的VMn…

实时视频分析的破局之道:蓝耘 MaaS 如何与海螺 AI 视频实现高效协同

一、蓝耘 MaaS 平台:AI 模型全生命周期管理的智能引擎 蓝耘 MaaS(Model-as-a-Service)平台是由蓝耘科技推出的 AI 模型全生命周期管理平台,专注于为企业和开发者提供从模型训练、推理到部署的一站式解决方案。依托云原生架构、高…

走进Java:String字符串的基本使用

❀❀❀ 大佬求个关注吧~祝您开心每一天 ❀❀❀ 目录 一、什么是String 二、如何定义一个String 1. 用双引号定义 2. 通过构造函数定义 三、String中的一些常用方法 1 字符串比较 1.1 字符串使用 1.2 字符串使用equals() 1.3 使用 equalsIgnoreCase() 1.4 cpmpareTo…

python系列之元组(Tuple)

不为失败找理由,只为成功找方法。所有的不甘,因为还心存梦想,所以在你放弃之前,好好拼一把,只怕心老,不怕路长。 python系列之元组(Turple) 一、元组是什么?——给新手的…

破解验证码新利器:基于百度OCR与captcha-killer-modified插件的免费调用教程

破解验证码新利器:基于百度OCR与captcha-killer-modified插件的免费调用教程 引言 免责声明: 本文提供的信息仅供参考,不承担因操作产生的任何损失。读者需自行判断内容适用性,并遵守法律法规。作者不鼓励非法行为,保…

批量删除 PPT 中的所有图片、某张指定图片或者所有二维码图片

PPT 文档中的图片如何删除呢?相信很多小伙伴或碰到类似的需求。比如我们需要删除 PPT 文档中的某一张图片或者某张二维码图片,如果每一页都有这张图片,或者有很多 ppt 都有同一张要删除的图片,我们应该怎么快速的完成删除呢&#…

大模型开发(六):LoRA项目——新媒体评论智能分类与信息抽取系统

LoRA项目——新媒体评论智能分类与信息抽取系统 0 前言1 项目介绍1.1 项目功能1.2 技术原理1.3 软硬件环境1.4 项目结构 2 数据介绍与处理2.1 数据集介绍2.2 数据处理2.3 数据导入器 3 模型训练3.1 配置文件3.2 工具函数3.3 模型训练3.4 模型评估 4 模型推理 0 前言 微调里面&…