news 2026/5/7 7:06:15

<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/26 4:34:53

基于Springboot+Vue的顺丰仓储管理信息系统源码文档部署文档代码讲解等

课题 本课题旨在开发并应用一套基于SpringBootVue的顺丰仓储管理信息系统&#xff0c;解决顺丰仓储运营中货物出入库繁琐、库存盘点低效、仓储资源调度不合理等问题&#xff0c;适配顺丰仓储规模化、高效化的运营需求。系统采用前后端分离架构&#xff0c;后端以SpringBoot为核…

作者头像 李华
网站建设 2026/5/7 7:05:31

基于Springboot+Vue的图书馆在线占座系统源码文档部署文档代码讲解等

课题介绍 本课题旨在设计并实现一套基于SpringBootVue的图书馆在线占座系统&#xff0c;解决校园图书馆座位资源紧张、人工占座混乱、座位利用率低、管理员管控不便等问题&#xff0c;适配学生自主占座与图书馆规范化管理的核心需求。系统采用前后端分离架构&#xff0c;后端以…

作者头像 李华
网站建设 2026/5/2 5:47:48

基于Springboot+Vue的图书馆座位预约系统源码文档部署文档代码讲解等

课题介绍 本课题旨在设计并实现一套基于SpringBootVue的图书馆座位预约系统&#xff0c;解决校园图书馆座位资源分配不均、人工预约繁琐、座位浪费严重及管理员管控低效等问题&#xff0c;适配学生座位预约与图书馆规范化管理的核心需求。系统采用前后端分离架构&#xff0c;后…

作者头像 李华
网站建设 2026/5/1 7:19:04

UI 设计组件的价值与实践+常用 UI 设计组件核心规范清单

在数字产品的界面世界里&#xff0c;设计组件就像是建筑中的标准化砖石&#xff0c;既支撑起界面的稳固性&#xff0c;又决定了体验的流畅度。从一张信息卡片到一条进度条&#xff0c;从一个分页控件到一整块瓷片区&#xff0c;这些看似微小的元素&#xff0c;正是构成优秀 UI …

作者头像 李华
网站建设 2026/5/3 8:33:19

2024年AI内容审核最新趋势:原生应用深度解析

2024 年 AI 内容审核最新趋势&#xff1a;原生应用深度解析 关键词&#xff1a;AI 内容审核、原生应用、图像识别、自然语言处理、机器学习模型、多模态融合、自动化 摘要&#xff1a;本文深入探讨 2024 年 AI 内容审核在原生应用领域的最新趋势。首先介绍 AI 内容审核的背景…

作者头像 李华
网站建设 2026/4/29 23:43:49

基于SpringBoot的智能医疗辅助系统(源码+lw+部署文档+讲解等)

课题介绍 本课题旨在设计并实现一套基于SpringBoot的智能医疗辅助系统&#xff0c;解决当前基层医疗中咨询响应滞后、健康档案管理零散、医疗知识普及不足、医护工作效率偏低等问题&#xff0c;适配基层医疗机构、社区卫生服务中心及家庭健康管理的智能辅助需求。系统以SpringB…

作者头像 李华