别让小数点坑了你的程序
写C语言代码时,整数运算干净利落,1 + 1 就是 2。但一旦碰上小数,比如用 float 或 double 做计算,结果可能就不那么靠谱了。你算出的 0.1 + 0.2 居然不等于 0.3?别急着怀疑数学,这其实是浮点数的常见“脾气”。
浮点数不是精确存储的
计算机用二进制表示数字,而很多十进制小数在二进制里是无限循环的。比如 0.1,在二进制中是个无穷小数,只能近似存储。这就导致精度丢失。
看个例子:
#include <stdio.h>
int main() {
float a = 0.1f;
float b = 0.2f;
float c = a + b;
if (c == 0.3f) {
printf("相等\n");
} else {
printf("不相等:%%.6f\n", c);
}
return 0;
}运行后你会发现输出的是“不相等:0.300000”,虽然看着像0.3,但内部值其实略高一点,直接用 == 判断就翻车了。
比较浮点数要用误差范围
判断两个浮点数是否“相等”,应该看它们的差值是否足够小。这个小的值叫 epsilon。
比如这样改:
#include <math.h>
#include <stdio.h>
#define EPSILON 1e-6
int main() {
float a = 0.1f;
float b = 0.2f;
float c = a + b;
if (fabs(c - 0.3f) < EPSILON) {
printf("可以认为相等\n");
}
return 0;
}用 fabs 取绝对值,再和一个很小的数比较,这才是稳妥的做法。
float 和 double 别混用
float 是单精度,大概7位有效数字;double 是双精度,约15位。混用时容易因隐式转换引入误差。
比如:
float f = 1.23456789f;
double d = f; // 此时精度已经损失了如果你需要高精度计算,全程用 double 更保险,也别随便把 double 强转成 float。
注意编译器优化的影响
有些编译器在优化时会调整浮点运算顺序,比如把 (a + b) + c 改成 a + (b + c)。虽然数学上等价,但浮点运算中顺序不同可能导致结果微小差异。
如果项目对数值稳定性要求高,比如科学计算或金融相关,建议关闭某些激进优化,或者使用 -ffloat-store 这类编译选项(GCC)来限制中间结果的精度扩展。
格式化输出也要小心
用 printf 输出 float 或 double 时,别图省事全用 %f。默认只显示6位小数,可能掩盖真实值。
想看清细节,可以指定精度:
printf("%.10f\n", 0.1f); // 显示更多位,看到真实近似值这样你就能看到它其实是 0.1000000015 左右。
能用整数就别用浮点
比如处理金额,与其用 1.99 元,不如存成 199 分。用整数运算避免所有浮点问题。等展示时再除以100,转换成小数形式输出。
这招在嵌入式、交易系统里很常见,简单又可靠。