题目

编写程序,演示浮点数计算中的精度截断误差:计算 $0.1 + 0.2$ 并检验其是否严格等于 $0.3$。展示直接比较 <code>==</code> 的灾难性错误,并给出基于机器精度 <code>eps</code> 与自定义绝对容差 $\epsilon$ 的正确比较范式。

输入格式:无需外部输入。

输出格式:展示直接比较结果、真实数值残差、以及基于容差判等的正确布尔输出。

数据范围与约定:浮点计算本质。

思路与算法

1. 二进制无法精确表示 0.1
十进制小数 0.1 转化为二进制是无限循环小数,在 IEEE 754 双精度下必然被截断,导致 $0.1 + 0.2 = 0.3000000000000000444...$。

2. 严格禁用 == 比较浮点数
任何经过乘除开方累加后的浮点数,直接写 a == b 几乎必定偶发性判断失误,形成幽灵 Bug。

3. 容差判定准则
绝对容差比较法:abs(a - b) < 1e-12;或者利用机器精度:abs(a - b) <= tol * max(abs(a), abs(b))。

完整程序

% Octave / MATLAB 第50题:浮点数容差判等
a = 0.1 + 0.2;
b = 0.3;

% 1. 错误的直接比较
is_equal_wrong = (a == b);

% 2. 观察实际微小残差
diff_val = a - b;

% 3. 正确的工程容差判等 (设定容差 tol)
tol = 1e-12;
is_equal_correct = (abs(a - b) < tol);

fprintf("0.1 + 0.2 的值: %.17f\n", a);
fprintf("0.3       的值: %.17f\n", b);
fprintf("直接等号比较 (a == b): %d (错误判定为不等!)\n", is_equal_wrong);
fprintf("两者真实差值 (a - b): %.2e\n", diff_val);
fprintf("基于容差判等 (abs(a - b) < 1e-12): %d (正确识别相等)\n", is_equal_correct);

运行示例

输出:

0.1 + 0.2 的值: 0.30000000000000004
0.3       的值: 0.29999999999999999
直接等号比较 (a == b): 0 (错误判定为不等!)
两者真实差值 (a - b): 5.55e-17
基于容差判等 (abs(a - b) < 1e-12): 1 (正确识别相等)