面试官:为什么 0.1+0.1=0.2,却偏偏 0.1+0.2≠0.3?

67 阅读4分钟

沉默是金,总会发光

大家好,我是沉默

面试官问:“0.1+0.2 为什么不等于 0.3?”我笑了,但他又补一句:“那为什么 0.1+0.1 又等于 0.2?”

这题我当时也懵了。
背会“浮点数精度问题”没用,面试官根本不想听口诀。
他想知道:你,到底懂不懂计算机怎么存 0.1?

**-**01-

这题的坑:要懂底层逻辑

小林在面试时被问到:

“为什么 0.1+0.2 ≠ 0.3?”
“那为啥 0.1+0.1 又等于 0.2?”

他脱口而出:“因为 0.1 不能被二进制精确表示!”

面试官点点头,又追问一句:“那为什么两个不精确的数相加,反而等于精确的 0.2 呢?”

小林:“呃……这……可能是巧合吧……”

其实,这不是巧合,而是 IEEE 754 浮点数的“舍入抵消”机制在起作用。

图片

- 02-

计算机是怎么存小数的?

在计算机眼里,所有浮点数都是科学计数法 + 二进制表示的近似值。

IEEE 754 双精度浮点数结构(Java 的 double

部分位数含义示例(以 0.1 为例)
符号位1正负号,0 为正,1 为负0
指数位11记录指数 + 偏移量(1023)-4 → 存 1019
尾数位52存储有效二进制小数部分(舍入后)1001100…(循环)

重点
0.1 的二进制是个“无限循环小数”:

0.1₁₀ = 0.00011001100110011...(0011 无限循环)

计算机无法完整存下,只能取前 52 位,然后做舍入(rounding)

所以——计算机存的“0.1”,其实是个近似值,不是数学意义上的 0.1。

图片

- 03-

案例拆解

案例1:0.1 + 0.1 = 0.2(误差抵消)

两个“近似 0.1”相加:

0.0001100110011... × 2^0+0.0001100110011... × 2^0=0.001100110011...₂

刚好等于 0.2 的二进制!
而且 0.2 的循环模式刚好能被 52 位“完整存下”,所以结果精确无误差

验证

System.out.println(new BigDecimal(0.1).add(new BigDecimal(0.1)));// 输出:0.200000000000000011102230246251565404236316680908203125System.out.println(new BigDecimal(0.2));// 输出:0.200000000000000011102230246251565404236316680908203125

两者完全一致 —— 计算机判定:相等 

案例2:0.1 + 0.2 ≠ 0.3(误差叠加)

0.10.000110011...0.20.00110011...相加 → 0.0100110011...

看似是 0.3,但转换成 IEEE 754 存储后,循环部分被截断、舍入,误差没抵消,反而叠加

验证

System.out.println(new BigDecimal(0.1).add(new BigDecimal(0.2)));// 0.3000000000000000444089209850062616169452667236328125System.out.println(new BigDecimal(0.3));// 0.299999999999999988897769753748434595763683319091796875

不一样!
这就是“0.1+0.2≠0.3”的根源:二进制循环 + 舍入误差叠加

**-****04-**总结

面试模板回答:3步搞定

步骤回答内容举例或关键词
Step 1原理说明:浮点数采用 IEEE 754 存储,小数转二进制会出现无限循环,只能存近似值。“0.1 在二进制中无限循环,存储时被舍入”
Step 2对比案例:两个近似值相加时,误差可能抵消(0.1+0.1)或叠加(0.1+0.2)。“所以一个等,一个不等”
Step 3工程建议:避免浮点误差,用 BigDecimal 或整数化处理。“金额计算用分,不用 double”

举例回答模板:

“这是 IEEE 754 浮点数精度问题。像 0.1 这样的数在二进制中是无限循环小数,只能被舍入成近似值。
0.1+0.1 时误差抵消,结果等于 0.2;但 0.1+0.2 时误差叠加,和 0.3 的存储值不一致。
实际开发中要用 BigDecimal 或整数计算来避免精度丢失。”

开发中怎么避坑?

金额计算
用 BigDecimal(String),别用 new BigDecimal(double)

BigDecimal a = new BigDecimal("0.1");BigDecimal b = new BigDecimal("0.2");System.out.println(a.add(b)); // 精确等于0.3

分制法(整数化)
金额统一乘以 100,用分来算:

int total10 + 20; // 单位分System.out.println(total / 100.0); // 输出0.3

打印调试
遇到异常浮点结果,用 BigDecimal 打印真实存储值。

会用的人,不怕“陷阱题”

浮点数这题,其实不是考死记硬背,而是考你能否:

  • 从“现象”追到“原理”
  • 从“误差”说到“工程实践”

面试官要的是一个“懂底层逻辑、又能写出可靠代码”的你。

你面试时遇到过哪些看似简单、实则坑人题?
留言聊聊,也许下一篇我们就一起拆!

图片

**-****05-**粉丝福利

站在职业的十字路口,我们或许都曾感到迷茫:




投出的简历总是没有回音?




面试时不知如何展现自己的优势?




未来的职场道路该如何规划?




技术管理能力提升,如何跨越第一步?




如果你正在经历这些,我很乐意用我的经验为你提供一些帮助。




无论是修改简历、1对1求职陪跑,职业规划咨询,




还是迈向技术Leader或提升管理效能,




欢迎你加我,我们像朋友一样聊聊。