C++ 或其他编程语言中直接使用 == 来比较两个浮点数(float 或 double)是不安全的,因为浮点数存在精度误差(round-off errors)。这种误差源于浮点数的存储方式导致数值计算过程中出现微小的偏差。

1、 基本区别

floatdouble 都是用于表示浮点数的数据类型,但它们在精度(precision)和内存大小(storage size)上有显著区别。

属性

float

double

字节大小

4 bytes(32 位)

8 bytes(64 位)

精度

约 6~7 位十进制数字

约 15~16 位十进制数字

表示范围

±3.4×10⁻³⁸ ~ ±3.4×10³⁸

±1.7×10⁻³⁰⁸ ~ ±1.7×10³⁰⁸

默认类型

否(需要加f后缀)

是(默认浮点字面值)

2、精度损失问题

差异在进行数值计算时会导致精度损失(loss of precision)问题,特别是在比较两个浮点数是否相等时。

#include <iostream>
#include <iomanip>
using namespace std;

int main() {
    float f = 1.0f / 3.0f;
    double d = 1.0 / 3.0;

    cout << fixed << setprecision(10);
    cout << "float:  " << f << endl;
    cout << "double: " << d << endl;
    return 0;
}

3、浮点数比较问题

由于浮点数存在精度误差,不能直接使用 == 比较浮点数是否相等,应使用一个 容差值(epsilon)。

#include <cmath>  // fabs
#include <iostream>
using namespace std;

bool isEqual(double a, double b, double epsilon = 1e-9) {
    return fabs(a - b) < epsilon;
}

int main() {
    double x = 0.1 + 0.2;
    double y = 0.3;

    cout << boolalpha << isEqual(x, y) << endl;  // 输出: true
}

4、epsilon 的含义

epsilon 表示一个允许的误差范围,用于容忍计算中由于精度问题引起的细微差异。一般来说,float 类型使用 1e-5 ~ 1e-6 的 epsilon,double 类型使用 1e-9 ~ 1e-10 的 epsilon。

#include <iostream>
#include <cmath>

bool isAlmostEqual(double a, double b, double epsilon = 1e-9) {
    return std::fabs(a - b) < epsilon;
}

int main() {
    double x = 0.1 + 0.2;
    double y = 0.3;

    if (isAlmostEqual(x, y)) {
        std::cout << "x 和 y 近似相等" << std::endl;
    } else {
        std::cout << "x 和 y 不相等" << std::endl;
    }
}

推荐文档