JavaScript 金額運算精度丟失問題及解決方案

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.pswp.cn/pingmian/72820.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/72820.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/72820.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Docker安裝,并pullMySQL和redis

卸載原Docker 您的 Linux 發行版可能提供非官方的 Docker 軟件包,這可能與 Docker 提供的官方軟件包沖突。在安裝 Docker Engine 正式版之前,您必須先卸載這些軟件包。 sudo dnf remove docker \ docker-client \ docker-client-latest \ docker-common…

國內首臺太空采礦機器人亮相,宇宙資源開發邁入新階段

隨著地球資源的日益枯竭,人類將目光投向了浩瀚的宇宙。太空采礦作為一項前沿科技,正逐步從科幻走向現實。近日,中國礦業大學成功研制出國內首臺太空采礦機器人,標志著我國在太空資源開發領域邁出了重要一步。 太空采礦并非新鮮概念…

簡介PyCDE:Python CIRCT Design Entry

簡介PyCDE:Python CIRCT Design Entry 引言 在硬件設計和驗證領域,隨著設計復雜性的增加,傳統的方法往往難以滿足現代設計的需求。PyCDE(Python CIRCT Design Entry)作為CIRCT項目的一部分,旨在為硬件設計…

市場熱點復盤20240319

以下是對當前市場熱點板塊的分析總結,按邏輯分類如下: 一、機器人產業鏈核心標的 1. 減速器與核心部件 襄陽軸承:直接受益人形機器人減速器軸承需求,技術國內領先。金帝股份:聚焦機器人手指關節諧波減速機保持架&am…

目標檢測——清洗數據

清洗VOC格式數據集代碼示例 import os import xml.etree.ElementTree as ETdef process_annotations(image_folder, annotation_folder):# 遍歷標簽文件夾中的所有XML文件for xml_file in os.listdir(annotation_folder):if not xml_file.endswith(.xml):continuexml_path os…

Kubeasz工具快速部署K8Sv1.27版本集群(二進制方式)

文章目錄 一、基本信息二、服務器初始化操作三、使用Kubeasz部署K8S集群四、驗證集群 一、基本信息 1、部署需要滿足前提條件: 注意1:確保各節點時區設置一致、時間同步;注意2:確保在干凈的系統上開始安裝;注意3&…

RG-S3760應用協議配置

RG-S3760應用協議配置 1. dhcp 服務配置 提問:如何在設備上開啟dhcp 服務,讓不同VLAN 下的電腦獲得相應的IP 地址? 回答: 步驟一:配置VLAN 網關IP 地址,及將相關端口劃入相應的VLAN 中 S3760#con t S…

Java 文件和IO流基礎(生動形象版)

系列文章目錄 Java文件和IO流基礎部分 文件VSIO流 文章目錄 系列文章目錄前言一、文件的定義和理解: 1.專業定義: 2.文件系統和路徑: 二、IO流的定義和分類 1.定義:2.流的分類:修飾器模式的核心作用:基礎結…

Linux驅動學習筆記(四)

高級字符設備進階 1.一個完整的IO過程包含以下幾個步驟:1應用程序向操作系統發起IO調用請求(系統調用);2操作系統準備數據,把IO設備的數據加載到內核緩沖區;3操作系統拷貝數據,把內核緩沖區的數據從內核空間拷貝到應用…

el-table的行向上移動向下移動,刪除選定行

<template><el-table :data"tableData" border style"width: 100%"><!-- 其他列 --><el-table-column label"ID"><template slot-scope"scope">{{ scope.$index }}</template></el-table-colu…

人工智能之數學基礎:矩陣的降維

本文重點 在現實世界中,我們經常會遇到高維數據。例如,圖像數據通常具有很高的維度,每個像素點都可以看作是一個維度。高維數據不僅會帶來計算和存儲上的困難,還可能會導致 “維數災難”,即隨著維度的增加,數據的稀疏性和噪聲也會增加,從而影響數據分析的效果。因此,我…

2025年,電腦還需要分區嗎?

隨著2025年的到來&#xff0c;電腦存儲空間已經不像以前那么金貴&#xff0c;固態硬盤&#xff08;SSD&#xff09;容量更大、速度更快&#xff0c;云存儲也成了日常標配。許多人開始質疑&#xff1a;電腦還需要像以前那樣分區嗎&#xff1f; 一、分區到底是什么意思&#xff…

Springboot項目集成maven-assembly-plugin進行打包

通常我們將應用部署到服務器的某個目錄下&#xff0c;一般情況下我們會提供像target&#xff08;存放應用jar包&#xff09;&#xff0c;bin&#xff08;項目啟動/停止腳本&#xff09;&#xff0c;config&#xff08;項目配置文件&#xff09;&#xff0c;logs&#xff08;項目…

CSS3 基礎布局技術與響應式設計

1. CSS3 基礎與布局技術 1.1 Flexbox 布局 Flexbox 是一種一維布局模型&#xff0c;適合用于在一個方向上&#xff08;行或列&#xff09;排列元素。 基本概念&#xff1a; 容器&#xff08;Container&#xff09;&#xff1a;應用 display: flex; 的元素。項目&#xff08…

鴻蒙NEXT項目實戰-百得知識庫01

代碼倉地址&#xff0c;大家記得點個star IbestKnowTeach: 百得知識庫基于鴻蒙NEXT穩定版實現的一款企業級開發項目案例。 本案例涉及到多個鴻蒙相關技術知識點&#xff1a; 1、布局 2、配置文件 3、組件的封裝和使用 4、路由的使用 5、請求響應攔截器的封裝 6、位置服務 7、三…

【DeepSeek應用】本地部署deepseek模型后,如何在vscode中調用該模型進行代碼撰寫,檢視和優化?

若已成功在本地部署了 DeepSeek 模型(例如通過 vscode-llm、ollama 或私有 API 服務),在 VS Code 中調用本地模型進行代碼撰寫、檢視和優化的完整流程如下: 1. 準備工作:確認本地模型服務狀態 模型服務類型: 若使用 HTTP API 服務(如 FastAPI/Flask 封裝),假設服務地址…

jenkins 配置郵件問題整理

版本&#xff1a;Jenkins 2.492.1 插件&#xff1a; A.jenkins自帶的&#xff0c; B.安裝功能強大的插件 配置流程&#xff1a; 1. jenkins->系統配置->Jenkins Location 此處的”系統管理員郵件地址“&#xff0c;是配置之后發件人的email。 2.配置系統自帶的郵件A…

Android Coil3階梯preload批量Bitmap拼接扁平寬圖,Kotlin

Android Coil3階梯preload批量Bitmap拼接扁平寬圖&#xff0c;Kotlin <uses-permission android:name"android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name"android.permission.READ_EXTERNAL_STORAGE" /><uses-p…

C++基礎 [八] - list的使用與模擬實現

目錄 list的介紹 List的迭代器失效問題 List中sort的效率測試 list 容器的模擬實現思想 模塊分析 作用分析 list_node類設計 list 的迭代器類設計 迭代器類--存在的意義 迭代器類--模擬實現 模板參數 和 成員變量 構造函數 * 運算符的重載 運算符的重載 -- 運…

【系統架構設計師】操作系統 - 特殊操作系統 ③ ( 微內核操作系統 | 單體內核 操作系統 | 內核態 | 用戶態 | 單體內核 與 微內核 對比 )

文章目錄 一、微內核操作系統1、單體內核 操作系統2、微內核操作系統 引入3、微內核操作系統 概念4、微內核操作系統 案例 二、單體內核 與 微內核 對比1、功能對比2、單體內核 優缺點3、微內核 優缺點 一、微內核操作系統 1、單體內核 操作系統 單體內核 操作系統 工作狀態 : …