《Java 100 天进阶之路》第40篇:浮点数转成十进制问题

第40篇:浮点数转成十进制问题

📌 系列导航《Java 100 天进阶之路》完整目录 |

⬅️ 上一篇:第39篇:Java泛型方法的定义和使用 |

➡️ 下一篇:第41篇:GET和POST的区别、堆和栈的区别


一、核心知识点

  • 浮点数的二进制表示(IEEE 754 标准)
  • 精度丢失原因:十进制小数无法用二进制精确表示(如 0.1)
  • 典型问题:0.1 + 0.2 != 0.3
  • 解决方案:BigDecimal、整数转换、误差阈值比较
  • BigDecimal 的正确使用(用字符串构造)

二、通俗讲解(1分钟开心学)

1. 为什么浮点数不精确?

计算机使用二进制存储数据。十进制小数在二进制中可能是无限循环的,比如 0.1 转换为二进制是 0.0001100110011...(无限循环)。内存有限,只能近似存储,所以运算时会产生微小误差。

2. 经典案例

java 复制代码
System.out.println(0.1 + 0.2); // 0.30000000000000004

3. 如何正确比较浮点数?

  • 误差范围法 :判断两个浮点数差的绝对值小于一个很小的数(如 1e-6)。
  • BigDecimal:精确的十进制运算,适合金融计算。
  • 整数转换:将小数转为整数计算,例如用"分"代替"元"。

4. BigDecimal 陷阱

new BigDecimal(0.1) 仍然不精确,因为 0.1 本身已经是不精确的 double。正确方式:new BigDecimal("0.1")BigDecimal.valueOf(0.1)

生活类比

浮点数误差就像你用一米的尺子去量一根木棍,木棍长度是 0.1 米,但你的尺子最小刻度是 0.125 米(二进制分数近似),你只能量出 0.125 米或 0.0 米。多次测量后误差累积。

三、实操代码案例 + 场景说明

场景:做电商的金额计算,必须精确到分。

java 复制代码
import java.math.BigDecimal;
import java.math.RoundingMode;

public class FloatDecimalDemo {
    public static void main(String[] args) {
        // 1. 浮点数误差演示
        double a = 0.1;
        double b = 0.2;
        double c = 0.3;
        System.out.println(a + b == c);   // false
        System.out.println(a + b);        // 0.30000000000000004
        
        // 2. 误差比较法
        final double EPS = 1e-6;
        if (Math.abs((a + b) - c) < EPS) {
            System.out.println("近似相等");
        }
        
        // 3. BigDecimal 正确使用
        BigDecimal bd1 = new BigDecimal("0.1");
        BigDecimal bd2 = new BigDecimal("0.2");
        BigDecimal sum = bd1.add(bd2);
        System.out.println(sum);               // 0.3
        System.out.println(sum.compareTo(new BigDecimal("0.3")) == 0); // true
        
        // 4. BigDecimal 做金融计算(售价、折扣)
        BigDecimal price = new BigDecimal("19.99");
        BigDecimal discount = new BigDecimal("0.85");
        BigDecimal finalPrice = price.multiply(discount).setScale(2, RoundingMode.HALF_UP);
        System.out.println("折后价:" + finalPrice); // 16.99
        
        // 5. 整数转换法(金额用分表示)
        long priceInCents = 1999;  // 19.99 元
        long discountPercent = 85; // 八五折
        long finalCents = priceInCents * discountPercent / 100;
        System.out.println("折后分:" + finalCents); // 1699 分 = 16.99 元
    }
}

四、避坑要点

错误/误区 后果 正确做法
直接用 == 比较浮点数 可能永远为 false(即使数值接近) 使用误差范围或 BigDecimal
new BigDecimal(0.1) 得到的不是精确 0.1 new BigDecimal("0.1")BigDecimal.valueOf(0.1)
在循环中累加浮点数 误差累积,结果偏差大 累加用 BigDecimal 或整数
浮点数直接输出或格式化不控制精度 显示很多位小数 String.format("%.2f", d)BigDecimal.setScale

五、面试高频考点

Q1:为什么 0.1 + 0.2 != 0.3

0.1 和 0.2 在二进制中是无限循环小数,计算机只能近似存储,相加后误差累积导致结果略大于 0.3。

Q2:如何正确比较浮点数?

  1. BigDecimal;2. 设定误差阈值 Math.abs(x - y) < 1e-6;3. 转换为整数(如货币用分)。

Q3:BigDecimaldouble 的区别?

BigDecimal 精确十进制,适合金融计算,但性能较低;double 近似值,性能高,适合科学计算。

六、练习题

  1. 计算1.0 - 0.9 的结果是什么?为什么?
  2. 编程 :使用 BigDecimal 计算商品总价:单价 19.99,数量 3,折扣 9.0 折,保留两位小数。
  3. 简答 :为什么银行系统使用 BigDecimal 而不是 double

📊 你的学习进度

  • 当前:第40篇 / 共44篇 · 第六阶段:NIO、泛型、JVM内幕、字节码(第36~44篇)
  • ✅ 已完成:第1~39篇
  • 📖 正在学:第40篇
  • ⏳ 待学习:第41~44篇

👉 📚 完整目录 & 学习指南 | 🔥 订阅本专栏,不错过每一篇

💡 本专栏每篇都包含:避坑表 + 面试高频考点 + 练习题。每天30分钟,100天拿offer!


👉 下一篇文章预告

《第41篇:GET和POST的区别、堆和栈的区别》

内容简介:GET vs POST(参数位置/长度/安全/幂等)、堆与栈存储内容、栈溢出与堆溢出。

💡 学完这篇,你将彻底分清网络请求的两种方式和JVM内存的两大区域。

📌 《Java 100 天进阶之路 | 从入门到上岗就业》 每天一篇,建议收藏 + 关注 ,一起100天拿offer!

👉 点击关注我,更新后第一时间收到推送!

相关推荐
lhldsg9 分钟前
社区健身系统开发实战:从需求分析到落地部署全流程指南
java·开发语言·小程序·需求分析
李高钢10 分钟前
C# WPF Prism 进阶(三):导航(Navigation)深入
开发语言·c#·wpf
冯汉栩11 分钟前
Swift Control DashLineView(虚线)
开发语言·ios·swift
覆东流17 分钟前
4.Java运算符与表达式
java·开发语言·后端
JacksonMx26 分钟前
ContentCachingRequestWrapper 实战:解决请求体“只能读一次”的官方方案
java·spring boot·spring
马丁玩编程37 分钟前
GitHub 3.5k Star 之后,Ragent AI 框架新版本来了
后端·面试·github
微石科技38 分钟前
医疗设备维保如何从被动维修转向预防管理?宁波微石科技让运行数据提前发信号
java·后端·struts
AINative软件工程38 分钟前
LLM 应用的 Warm-Up 工程实践:冷启动延迟从 12 秒砍到 800ms 的 5 个工程手段
后端·llm·ai编程
SomeB1oody43 分钟前
【RustyML入门】5.1. 回归指标
开发语言·后端·机器学习·rust·教程
学计算机的计算基44 分钟前
TCP 传输层硬核整理:三次握手、四次挥手、拥塞控制一次讲透
java·网络·笔记·网络协议·算法