卡码笔记
首页
计算机基础
C++
Java
面经
笔记广场 (opens new window)
代码随想录 (opens new window)
首页
计算机基础
C++
Java
面经
笔记广场 (opens new window)
代码随想录 (opens new window)
  • 基础与语法

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

  • STL 与容器

  • 内存管理

  • C++11 与现代 C++

  • 智能指针

  • 并发与 I/O

# c++中浮点数相等比较的正确方法

面试时没有回答好问题是很正常的,被面试官质疑时,要有今天不会明天会的底气,面后做好复盘,不在同一道题目上跌倒第二次,今天就从 c++中浮点数相等比较的正确方法 背起来

# 简要回答

由于浮点数的精度限制和表示误差,直接使用 == 比较通常不可靠。

正确方法是使用误差容忍度比较,包括绝对误差、相对误差或结合两者的ULP(Unit in the Last Place)比较。

# 详细回答

浮点数在计算机中采用IEEE 754标准表示,存在以下问题:

精度限制:浮点数有有限的精度位数,无法精确表示所有实数

舍入误差:运算过程中会产生舍入误差,累积后可能显著

表示误差:某些十进制数在二进制中无法精确表示(如0.1)

不同运算顺序可能产生不同结果

正确比较方法:

绝对误差比较:适用于数值范围已知的情况

相对误差比较:适用于数值范围变化较大的情况

ULP比较:基于浮点数表示的精度的比较方法

结合绝对和相对误差:综合两种方法的优势

# 代码示例

#include <iostream>
#include <cmath>
#include <limits>
#include <algorithm>

class FloatComparison {
public:
    // 方法1: 绝对误差比较
    static bool almostEqualAbsolute(float a, float b, float absEpsilon = 1e-5f) {
        return std::fabs(a - b) <= absEpsilon;
    }

    // 方法2: 相对误差比较
    static bool almostEqualRelative(float a, float b, float relEpsilon = 1e-5f) {
        float diff = std::fabs(a - b);
        float scale = std::max(std::fabs(a), std::fabs(b));
        return diff <= scale * relEpsilon;
    }

    // 方法3: 结合绝对和相对误差
    static bool almostEqual(float a, float b,
                           float absEpsilon = 1e-5f,
                           float relEpsilon = 1e-5f) {
        float diff = std::fabs(a - b);

        // 如果差值很小,直接返回true(处理接近0的情况)
        if (diff <= absEpsilon) {
            return true;
        }

        // 否则使用相对误差比较
        float scale = std::max(std::fabs(a), std::fabs(b));
        return diff <= scale * relEpsilon;
    }

    // 方法4: 基于机器精度的比较
    static bool almostEqualMachine(float a, float b, int ulp = 2) {
        return std::fabs(a - b) <=
               std::numeric_limits<float>::epsilon() *
               std::max(std::fabs(a), std::fabs(b)) * ulp;
    }
};

void basic_comparison_demo() {
    std::cout << "=== 基础浮点数比较演示 ===" << std::endl;

    float a = 0.1f + 0.2f;
    float b = 0.3f;

    std::cout << "a = 0.1 + 0.2 = " << a << std::endl;
    std::cout << "b = 0.3 = " << b << std::endl;
    std::cout << "a - b = " << (a - b) << std::endl;

    std::cout << "\n直接比较 (a == b): " << (a == b ? "true" : "false") << std::endl;
    std::cout << "绝对误差比较: " << (FloatComparison::almostEqualAbsolute(a, b) ? "true" : "false") << std::endl;
    std::cout << "相对误差比较: " << (FloatComparison::almostEqualRelative(a, b) ? "true" : "false") << std::endl;
    std::cout << "结合比较: " << (FloatComparison::almostEqual(a, b) ? "true" : "false") << std::endl;
    std::cout << "机器精度比较: " << (FloatComparison::almostEqualMachine(a, b) ? "true" : "false") << std::endl;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

# 知识拓展

浮点数表示基础 IEEE 754单精度浮点数结构:

1位符号位

8位指数位

23位尾数位

常见浮点数陷阱

累积误差:多次运算后误差累积

吸收现象:大数加小数时小数被忽略

抵消现象:相近数相减导致精度丢失

非结合性:(a + b) + c ≠ a + (b + c)

  • 知识图解

image

image

  • 适用场景

推荐使用绝对误差的场景:

物理测量数据:传感器读数,已知测量精度

固定范围的数值:颜色值(0-1)、标准化数据

游戏开发:位置坐标、物理模拟

用户界面:像素坐标、动画参数

推荐使用相对误差的场景:

科学计算:数值分析、模拟计算

工程计算:结构分析、流体力学

金融计算:利率、汇率计算

统计分析:大数据处理

  • 面试官很能追问

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

A1: 因为0.1和0.2在二进制中是无限循环小数,无法在有限精度的浮点数中精确表示。计算过程中会产生舍入误差,累积后导致结果与0.3有微小差异。

Q2: 什么时候应该直接使用==比较浮点数?

A2: 在以下情况可以使用==:

比较整数值的浮点数表示

检查是否为特定的已知值(如0.0、1.0)

与无穷大或NaN比较时(但要用isinf()、isnan()更好)

位模式完全相同的比较

Q3: 如何处理浮点数的NaN和无穷大? A3: 使用标准库函数:

std::isnan(x) 检查是否为NaN

std::isinf(x) 检查是否为无穷大

std::isfinite(x) 检查是否为有限数 NaN与任何值(包括自己)比较都返回false。

Last Updated: 3/10/2026, 6:08:48 PM

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

评论

验证登录状态...

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