float 类型
float 是 C 语言的单精度浮点类型,通常占用 4 字节(32 位),按 IEEE 754 标准编码。精度约为 7 位有效十进制数字,范围约 ±3.4×10³⁸。它适合存储对精度要求不高的大规模浮点数据,能比 double 节省一半内存。
IEEE 754 编码
float 的 32 位按 IEEE 754 标准编码:
- 1 位符号位
- 8 位指数位
- 23 位尾数位
基本用法
float pi = 3.14159f; /* f 后缀表示 float 常量 */
float temperature = -15.5f;
printf("sizeof(float) = %zu\n", sizeof(float)); /* 通常是 4 */
float 的精度约为 7 位有效十进制数字,范围约 ±3.4×10³⁸:
#include <float.h>
printf("FLT_MIN = %e\n", FLT_MIN); /* 约 1.17×10⁻³⁸ */
printf("FLT_MAX = %e\n", FLT_MAX); /* 约 3.40×10³⁸ */
printf("FLT_EPSILON = %e\n", FLT_EPSILON); /* 约 1.19×10⁻⁷ */
浮点常量
浮点常量默认是 double 类型,必须加 f 或 F 后缀才能指定为 float:
3.14f /* float */
3.14F /* float */
3.14 /* double(默认) */
3.14e10f /* 科学计数法:3.14 × 10¹⁰,float 类型 */
C99 新增十六进制浮点常量,用于精确表示 IEEE 754 浮点数的每一位:
float f = 0x1.0p0f; /* 1.0 × 2⁰ = 1.0 */
float g = 0x1.8p1f; /* 1.5 × 2¹ = 3.0 */
printf("%a\n", f); /* C99:十六进制浮点格式输出 */
十六进制浮点的语法:0x + 十六进制整数部分 + . + 十六进制小数部分 + p + 二进制指数。这种表示法避免了十进制到二进制的转换误差。
格式化输入输出
printf 的 %f 对应 double,float 参数会自动提升为 double:
float f = 3.14159f;
printf("%f\n", f); /* 默认 6 位小数:3.141590 */
printf("%.2f\n", f); /* 2 位小数:3.14 */
scanf 读取 float 使用 %f:
float f;
scanf("%f", &f);
精度限制
float 只有约 7 位有效数字,累积运算会产生明显误差:
float f = 0.1f; /* 存储的是近似值 0.10000000149... */
float sum = 0.0f;
for (int i = 0; i < 1000000; i++)
sum += f; /* 累积误差 */
printf("%.6f\n", sum); /* 可能不是 100000.0 */
浮点数无法精确表示某些十进制小数,这是二进制表示的固有局限:
if (0.1f + 0.2f == 0.3f)
printf("Equal\n"); /* 通常不会输出! */
正确比较:使用误差范围而非精确相等:
#include <math.h>
#define EPSILON 1e-6f
int float_equal(float a, float b)
{
return fabsf(a - b) < EPSILON;
}
特殊浮点值
IEEE 754 定义了几个特殊值,float 同样适用:
#include <math.h>
float inf = 1.0f / 0.0f; /* inf:正无穷 */
float nan = 0.0f / 0.0f; /* nan:非数字 */
if (isnan(nan)) printf("Not a number\n");
if (isinf(inf)) printf("Infinity\n");
if (isfinite(inf)) printf("Finite\n");
NaN 的特性:任何涉及 NaN 的比较都为假,包括 NaN == NaN。
何时使用 float
| 场景 | 是否适合 float |
|---|---|
| 图形渲染(顶点坐标、颜色) | ✅ 精度足够,内存减半 |
| 传感器数据(温度、加速度) | ✅ 传感器精度通常有限 |
| 大规模数组(节省内存) | ✅ 如机器学习特征 |
| 金融计算 | ❌ 精度不足,用 double |
| 科学计算 | ❌ 累积误差大,用 double |
| 需要精确比较 | ❌ 无法精确表示十进制小数 |
常见错误
精度损失:
float f = 0.1f; /* 存储的是近似值 */
整数除法 vs 浮点除法:
int a = 5, b = 2;
float wrong = a / b; /* 整数除法:5/2 = 2,再转为 2.0 */
float right = (float)a / b; /* 浮点除法:2.5 */
比较浮点数是否相等:
if (x == 0.0f) /* 危险:x 可能是 0.0000001f */
/* ... */
if (fabsf(x) < 1e-6f) /* 安全:检查是否接近零 */
/* ... */