news 2026/4/18 12:09:56

<span class=“js_title_inner“>别用 new BigDecimal(0.1)!这是 90% Java 程序员都会踩的坑</span>

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
<span class=“js_title_inner“>别用 new BigDecimal(0.1)!这是 90% Java 程序员都会踩的坑</span>
关注我们,设为星标,每天7:30不见不散,每日java干货分享


🧮 浮点数:理想中的“精密数学”

在人类的直觉里,小数运算是天经地义的:

动作

代码行数 (理想状态)

描述

第一笔钱

1 行

double a = 0.1;

第二笔钱

1 行

double b = 0.2;

相加

1 行

double sum = a + b;

判断

1 行

if (sum == 0.3) pay();

结果

-

支付成功,账目平齐。

现实是:支付失败。因为sum的值是0.30000000000000004
你的代码走进了一个平行宇宙,那里0.3 != 0.3


🧬 第一关:二进制的“翻译丢失” (IEEE 754)

这是所有浮点数问题的根源。
计算机是二进制的(只有 0 和 1)。
人类是十进制的(0-9)。

恐怖故事:

  • • 整数0.5(十进制) =0.1(二进制)。这个能除尽,没问题。

  • • 小数0.1(十进制) =0.00011001100110011...(二进制)。

  • 发现了吗?它是无限循环小数!

就像你没法用“十进制”精确表示1/3(0.3333...) 一样,计算机也没法用“二进制”精确表示0.1
它只能截断,存一个“近似值”。
当你把两个“近似值”相加,误差就被放大了。


💸 第二关:消失的几分钱 (Financial Disaster)

这是电商和金融系统最容易踩的雷。

场景:
你在做一个电商后台。商品价格是19.90元,用户买了3个。
你写了:double total = 19.90 * 3;

恐怖故事:

  • • 你的预期:59.70

  • • 计算机的结果:59.699999999999996

后果:

  • 前端展示:用户看到了59.6999...,觉得你们系统有 Bug。

  • 数据库存入:如果你截取两位小数存入,可能变成了59.69少了 1 分钱。

  • 财务审计:累计几亿笔订单后,账面上莫名其妙少了几百万

  • 结局:程序员被祭天,因为涉嫌“贪污”那消失的 1 分钱。


♾️ 第三关:死循环的陷阱 (The Infinite Loop)

场景:
你想写一个循环,从 0 开始,每次加 0.1,直到等于 1。

for (double i = 0; i != 1.0; i += 0.1) { System.out.println("Running..."); }

恐怖故事:
这个循环永远不会停止

真相:

  • i的值变化:

  • • 0

  • • 0.1

  • • 0.2

  • 0.30000000000000004(这就是鬼故事的开始)

  • • ...

  • • 最后它会变成0.999999...然后直接跳到1.099999...

  • • 它永远不会精确地等于1.0

后果:
服务器 CPU 100%,线程卡死。你需要重启服务才能救活它。


🚀 第四关:价值 3.7 亿美元的 Bug (Ariane 5)

这是历史上最昂贵的浮点数事故。

时间:1996 年 6 月 4 日。
事件:欧洲航天局的阿里亚纳 5 号火箭首飞。
结果:发射后 37 秒,火箭在空中解体爆炸。

代码真相:
程序试图把一个64 位浮点数(火箭的水平速度)转换成一个16 位有符号整数
当时火箭速度太快,浮点数的值超过了 16 位整数的最大范围(32767)。
结果:溢出报错 (Overflow)-> 导航计算机死机 -> 备份计算机也死机(跑的是同一套代码) -> 火箭启动自毁程序。
损失:3.7 亿美元瞬间化为乌有。


🧟‍♂️ 第五关:NaN 的僵尸病毒

浮点数里有一个特殊值叫NaN (Not a Number)
它比如0.0 / 0.0或者Math.sqrt(-1)会产生。

恐怖故事:
NaN 有一个极其反直觉的特性:NaN 不等于 NaN
if (x == x)在 x 是 NaN 时,结果是false

后果:
如果你在一个列表中混入了一个NaN,然后对列表进行排序
排序算法(如 Timsort)依赖x > yx == y的比较逻辑。
因为NaN跟谁比都是错,排序可能会崩溃,或者陷入死循环,或者排出来的顺序是乱的。
NaN就像僵尸病毒,一旦进入你的数据流,所有的后续计算都会变成NaN


🛡️ 拆弹专家:如何正确算账?

既然浮点数这么不靠谱,我们该怎么办?

1. 金融计算:严禁使用 Float/Double

涉及钱的地方,必须使用高精度小数类

  • Java:BigDecimal

  • Python:decimal.Decimal

  • SQL:DECIMAL(10, 2)

正确姿势:

// 千万别用 new BigDecimal(0.1),因为它会把 0.1 的误差也存进去! // 要用 String 构造器 BigDecimal a = new BigDecimal("0.1"); BigDecimal b = new BigDecimal("0.2"); BigDecimal sum = a.add(b); // 结果真的是 0.3
2. 卑微的妥协:Epsilon 比较法

如果你非要用浮点数(比如做游戏、图形学计算),**永远不要用==**
要判断两个数是否“足够接近”。

正确姿势:

double EPSILON = 0.000001; if (Math.abs(a - b) < EPSILON) { // 认为是相等的 }
3. 变成整数:单位降级

把“元”转换成“分”来存储。

  • • 存1990分,而不是19.9元。

  • • 所有的计算全用整数(整数是没有精度丢失的)。

  • • 只在显示给用户看的时候,除以 100。


💡 终章:计算机的“失语”

计算机并不完美。
它引以为傲的计算能力,建立在二进制的沙滩上。
当你想用这堆沙子去构建人类十进制的大厦时,必须小心翼翼地填补那些**“精度的缝隙”**。

推荐阅读 点击标题可跳转

50个Java代码示例:全面掌握Lambda表达式与Stream API

16 个 Java 代码“痛点”大改造:“一般写法” VS “高级写法”终极对决,看完代码质量飙升!

为什么高级 Java 开发工程师喜爱用策略模式

精选Java代码片段:覆盖10个常见编程场景的更优写法

提升Java代码可靠性:5个异常处理最佳实践

为什么大佬的代码中几乎看不到 if-else,因为他们都用这个...

还在 Service 里疯狂注入其他 Service?你早就该用 Spring 的事件机制了

看完本文有收获?请转发分享给更多人

关注「java干货」加星标,提升java技能

❤️给个「推荐 」,是最大的支持❤️

.cls-1{fill:#001e36;}.cls-2{fill:#31a8ff;}

.cls-1{fill:#001e36;}.cls-2{fill:#31a8ff;}

.cls-1{fill:#001e36;}.cls-2{fill:#31a8ff;}

.cls-1{fill:#001e36;}.cls-2{fill:#31a8ff;}

.cls-1{fill:#001e36;}.cls-2{fill:#31a8ff;}

.cls-1{fill:#001e36;}.cls-2{fill:#31a8ff;}

.cls-1{fill:#001e36;}.cls-2{fill:#31a8ff;}

.cls-1{fill:#001e36;}.cls-2{fill:#31a8ff;}

.cls-1{fill:#001e36;}.cls-2{fill:#31a8ff;}

.cls-1{fill:#001e36;}.cls-2{fill:#31a8ff;}

.cls-1{fill:#001e36;}.cls-2{fill:#31a8ff;}

.cls-1{fill:#001e36;}.cls-2{fill:#31a8ff;}

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 2:02:42

基于Springboot+Vue的乡镇卫生所医用物资进销存系统源码文档部署文档代码讲解等

课题介绍 本课题旨在设计并实现一套基于SpringBootVue的乡镇卫生所医用物资进销存系统&#xff0c;解决当前乡镇卫生所医用物资采购无序、库存管控混乱、出入库登记繁琐、物资过期预警不足等问题&#xff0c;适配乡镇卫生所医用物资精细化管理的核心需求。系统采用前后端分离架…

作者头像 李华
网站建设 2026/4/18 2:05:34

MAVLink 通信协议 C++ 开发实战:从环境搭建到飞控通信全解析

前言 MAVLink&#xff08;Micro Air Vehicle Link&#xff09;是一款轻量级、低带宽、高可靠性的微小型无人机通信协议&#xff0c;由 PX4 团队主导设计&#xff0c;广泛应用于无人机、无人车、机器人等嵌入式系统的跨设备通信场景。其核心优势在于专为资源受限的硬件&#xf…

作者头像 李华
网站建设 2026/4/18 1:59:18

告别传统RAG的痛点!Agent Skills让知识库检索更智能(本地知识库搭建新思路:用Agent Skills实现渐进式检索)

文章目录 📖 介绍 📖 🏡 演示环境 🏡 📒 Agent Skills在知识库检索中的实践探索 📒 📝 传统RAG的局限性 📝 Agent Skills的核心设计理念 🎯 分层索引导航 🎯 先学习,再处理 🎯 渐进式检索 📝 实际应用场景对比 场景一:查询AI行业趋势 场景二:分析电…

作者头像 李华
网站建设 2026/4/18 1:57:22

基于multisim的波形发生与变换电路设计

设计正弦波振荡电路&#xff0c;要求产生1KHz的正弦波&#xff0c;并将1KHz的正弦波转换成1kHz的方波和三角波。 仿真图&#xff1a; 仿真演示与文件下载&#xff1a;基于multisim的波形发生与变换电路设计演示视频_哔哩哔哩_bilibili

作者头像 李华
网站建设 2026/4/18 1:59:41

淘宝评论数据采集 API 全解析【淘宝评论API】

一、官方 API 方案 1.1 核心接口概览 淘宝开放平台 (TOP) 提供的官方评论数据接口主要有以下 3 个&#xff0c;权限申请门槛较高&#xff0c;仅对企业 / 店铺商家开放&#xff0c;个人开发者无法申请&#xff1a; 接口名称功能描述适用场景taobao.item.review.get获取淘宝商…

作者头像 李华
网站建设 2026/4/18 1:59:49

打卡信奥刷题(2789)用C++实现信奥题 P3939 数颜色

P3939 数颜色 题目背景 大样例可在页面底部「附件」中下载。 题目描述 小 C 的兔子不是雪白的&#xff0c;而是五彩缤纷的。每只兔子都有一种颜色&#xff0c;不同的兔子可能有相同的颜色。小 C 把她标号从 1 到 nnn 的 nnn 只兔子排成长长的一排&#xff0c;来给他们喂胡萝…

作者头像 李华