JavaScript 浮点数计算精度错误示例

JavaScript 浮点数计算精度错误示例

在 JavaScript 中,浮点数精度问题源于其使用 IEEE 754 双精度浮点数标准(64位二进制表示)。这种表示法无法精确表示某些十进制小数,导致计算出现微小误差。以下是典型示例:

示例 1:基础加法错误
javascript 复制代码
// 预期:0.1 + 0.2 = 0.3
console.log(0.1 + 0.2 === 0.3);  // 输出:false
console.log(0.1 + 0.2);           // 输出:0.30000000000000004

原因分析
0.10.10.1 和 0.20.20.2 在二进制中是无限循环小数:

  • 0.110=0.0001100110011...20.1_{10} = 0.0001100110011..._20.110=0.0001100110011...2
  • 0.210=0.001100110011...20.2_{10} = 0.001100110011..._20.210=0.001100110011...2
    计算时发生二进制舍入误差。

示例 2:财务计算错误
javascript 复制代码
// 计算含税价(税率13%)
const price = 100.01;
const taxRate = 0.13;

// 预期:不含税价 = 100.01 / 1.13 ≈ 88.50442477876106
const result = price / (1 + taxRate);
console.log(result);  // 输出:88.50442477876106(看似正确)

// 但验证时出现偏差:
const verify = result * 1.13;
console.log(verify);  // 输出:100.01000000000001(多出0.00000000000001)

问题本质

浮点数的二进制表示无法精确等价于十进制 0.130.130.13,导致累积误差。


示例 3:乘法精度丢失
javascript 复制代码
// 计算商品总价(单价8.85元 × 数量3)
const total = 8.85 * 3;
console.log(total); // 输出:26.549999999999997(而非26.55)

关键点
8.858.858.85 在二进制中是 1000.1100110011...21000.1100110011..._21000.1100110011...2(无限循环),乘法放大舍入误差。


示例 4:比较操作失效
javascript 复制代码
const a = 0.3 - 0.2;  // 0.09999999999999998
const b = 0.2 - 0.1;  // 0.1

// 预期:a 和 b 应相等(0.3-0.2=0.2-0.1)
console.log(a === b);  // 输出:false

解决方案

使用误差范围比较:

javascript 复制代码
function isEqual(x, y, epsilon = 1e-10) {
  return Math.abs(x - y) < epsilon;
}
console.log(isEqual(a, b));  // 输出:true

精度问题本质

JavaScript 的数值范围限制:

  • 安全整数范围 :[−253,253][-2^{53}, 2^{53}][−253,253](即 [−9007199254740991,9007199254740991][-9007199254740991, 9007199254740991][−9007199254740991,9007199254740991])
  • 浮点数精度 :仅能精确表示分母为 2n2^n2n 的小数(如 0.5,0.250.5, 0.250.5,0.25),无法精确表示 0.1,0.20.1, 0.20.1,0.2 等。

解决方法

  1. 整数放大法(适合简单计算):

    javascript 复制代码
    // 将小数转为整数计算后再还原
    const calculate = (a, b) => (a * 1000 + b * 1000) / 1000;
    console.log(calculate(0.1, 0.2)); // 0.3
  2. 高精度库(推荐):

    javascript 复制代码
    // 使用 decimal.js
    import { Decimal } from 'decimal.js';
    const result = new Decimal(0.1).plus(0.2).toNumber();
    console.log(result); // 0.3
  3. 内置精度处理(ES6):

    javascript 复制代码
    // 使用 Number.EPSILON 比较
    console.log(Math.abs(0.3 - (0.1 + 0.2)) < Number.EPSILON); // true

⚠️ 在财务等敏感场景中,必须使用高精度库 (如 decimal.jsbig.js),整数放大法在超出安全范围时仍会出错。

相关推荐
一 乐17 小时前
婚纱摄影网站|基于ssm + vue婚纱摄影网站系统(源码+数据库+文档)
前端·javascript·数据库·vue.js·spring boot·后端
Boilermaker199217 小时前
[Java 并发编程] Synchronized 锁升级
java·开发语言
MM_MS17 小时前
Halcon变量控制类型、数据类型转换、字符串格式化、元组操作
开发语言·人工智能·深度学习·算法·目标检测·计算机视觉·视觉检测
꧁Q༒ོγ꧂18 小时前
LaTeX 语法入门指南
开发语言·latex
njsgcs18 小时前
ue python二次开发启动教程+ 导入fbx到指定文件夹
开发语言·python·unreal engine·ue
alonewolf_9918 小时前
JDK17新特性全面解析:从语法革新到模块化革命
java·开发语言·jvm·jdk
古城小栈18 小时前
Rust 迭代器产出的引用层数——分水岭
开发语言·rust
ghie909018 小时前
基于MATLAB的TLBO算法优化实现与改进
开发语言·算法·matlab
恋爱绝缘体118 小时前
2020重学C++重构你的C++知识体系
java·开发语言·c++·算法·junit
wuk99818 小时前
VSC优化算法MATLAB实现
开发语言·算法·matlab