卡码笔记-最强八股文
首页
计算机基础
C++
Java
Go
🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经
简历专栏
代码随想录 (opens new window)
首页
计算机基础
C++
Java
Go
🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经
简历专栏
代码随想录 (opens new window)
  • 本栏必读

    • 关于本专栏
    • C++学习路线
    • C++面试题系优化
  • 基础与语法

    • 介绍c++一下三大特性
    • 指针和引用的区别
    • 结构体和类的区别
    • 结构体与联合体的区别
    • static关键字和const关键字的作用
    • extern C的作用
    • volatile关键字的作用
    • inline函数与宏的区别与优劣
    • auto和decltype的区别
    • sizeof和strlen的区别
    • 浮点数比较方法
      • 简要回答
      • 详细回答
      • 知识拓展
    • 静态局部变量,全局变量,局部变量的特点,以及使用场景
    • C++中四种类型转换
  • 面向对象

  • STL 与容器

  • 内存管理

  • C++11 与现代 C++

  • 智能指针

  • 并发与 I/O

# C++ 浮点数比较

面试官问:"为什么浮点数不能直接用 == 比较?正确的比较方法是什么?"

这题看似简单,但很多人只能说出"因为有精度问题",问到具体原因(为什么 0.1 在二进制里是无限循环)、epsilon 该取多大、绝对误差和相对误差怎么选,就答不上来了。关键是从 IEEE 754 的表示原理出发理解问题的根源。

# 简要回答

浮点数不能直接用 == 比较,因为 IEEE 754 标准下,二进制浮点数无法精确表示所有十进制小数。比如 0.1 在二进制中是无限循环小数,存储时必须截断,产生表示误差。运算过程中误差会累积,导致 0.1 + 0.2 的结果不是精确的 0.3。

正确做法是用误差容忍度(epsilon)比较:判断两个浮点数的差的绝对值是否小于某个阈值,而不是判断是否严格相等。

# 详细回答

根本原因:二进制无法精确表示所有十进制小数

IEEE 754 单精度浮点数用 32 位存储:1 位符号、8 位指数、23 位尾数。尾数只有 23 位有效数字(约 7 位十进制精度),任何超出这个精度的信息都会被截断。

0.1 转成二进制是 0.0001100110011...(0011 无限循环),存储时必须在 23 位处截断。这个截断就是误差的来源——不是运算出了错,而是数字本身就没法精确表示。

三种比较方法

绝对误差比较:|a - b| < epsilon。简单直接,但 epsilon 是固定值,对大数不够精确(1000000.0 和 1000000.1 的差可能超过 epsilon),对极小数又太宽松。适合数值范围已知且固定的场景(比如颜色值 0~1、像素坐标)。

相对误差比较:|a - b| / max(|a|, |b|) < epsilon。按比例衡量误差,对大数和小数都公平。但当 a 和 b 接近 0 时会出问题(除以接近 0 的数导致结果爆炸)。适合数值跨度大的科学计算。

混合方法:先用绝对误差处理接近 0 的情况,再用相对误差处理一般情况。实际项目中最常用。

常见浮点数陷阱

  • 累积误差:循环中反复加 0.1,误差会越来越大
  • 吸收现象:1e20 + 1.0 == 1e20,小数被大数"吸收"
  • 抵消现象:两个相近的大数相减,有效数字急剧减少
  • 非结合性:(a + b) + c 不一定等于 a + (b + c)

浮点数比较方法

# 知识拓展

面试官可能追问:

Q1: 为什么 0.1 + 0.2 不等于 0.3?

因为 0.1 和 0.2 在二进制中都是无限循环小数,存储时各自被截断,各自带了一点误差。两个带误差的数相加,误差累积,结果是 0.30000000000000004 而不是精确的 0.3。这不是 C++ 的 bug,任何用 IEEE 754 的语言(Java、Python、JavaScript)都有这个问题。

Q2: epsilon 该取多大?

没有万能答案,取决于场景。对于 float(约 7 位有效数字),绝对误差通常取 1e-5 到 1e-6;对于 double(约 15 位有效数字),取 1e-9 到 1e-12。如果用相对误差,通常取 std::numeric_limits<float>::epsilon()(约 1.19e-7)的几倍。关键是要根据业务精度需求来定,而不是随便取一个"看起来很小"的数。

Q3: 什么时候可以直接用 == 比较浮点数?

极少数情况:比较的是整数值的浮点表示(如 3.0 == 3.0)、检查是否为字面量赋值的特定值(如判断是否为 0.0)、或者比较的两个值来自同一个赋值而没有经过任何运算。只要经过了运算(加减乘除),就不能用 ==。

Q4: NaN 有什么特殊行为?

NaN(Not a Number)是 IEEE 754 定义的特殊值,表示无效运算的结果(如 0.0/0.0、sqrt(-1))。它的特殊之处在于:NaN 和任何值比较(包括自己)都返回 false。所以 x != x 是判断 NaN 的一种方式,但更推荐用 std::isnan(x)。

Last Updated: 5/23/2026, 4:47:40 PM

← sizeof和strlen的区别 静态局部变量,全局变量,局部变量的特点,以及使用场景 →

评论

验证登录状态...

侧边栏 侧边栏
夜间模式 夜间
卡码简历 卡码简历
代码随想录 代码随想录
卡码投递表 卡码投递表🔥
2026实习校招群 2026群
添加客服微信 2026实习校招客服微信 PS:通过微信后,请发送姓名-学校-年级-2026实习/校招
支持卡码笔记 支持卡码笔记
鼓励/支持/赞赏Carl 卡码笔记赞赏码
1. 如果感觉本站对你很有帮助,也可以请Carl喝杯奶茶,金额大小不重要,心意已经收下
2. 希望大家都能梦想成真,有好的前程,加油💪