“Floating” 通常指的是 浮点数,这是一种用于表示带有小数部分的数字的数据类型,与只能表示整数的 int 类型不同,浮点数可以表示像 14、-0.001、5e10 这样的数值。

在 C 语言中,处理浮点数主要涉及三种基本类型:float、double 和 long double。
浮点数类型
float (单精度浮点数)
- 大小: 通常为 4 个字节 (32 位)。
- 精度: 提供 约 6-7 位有效数字。
- 用途: 当对内存占用要求非常严格,且数值范围和精度要求不高时使用,在游戏开发中用于图形坐标,或者在嵌入式系统中。
double (双精度浮点数)
- 大小: 通常为 8 个字节 (64 位)。
- 精度: 提供 约 15-16 位有效数字。
- 用途: 这是 C 语言中最常用的浮点类型,提供了很好的精度和范围的平衡,在大多数科学计算、金融计算等场景中,默认就使用
double。
long double (长双精度浮点数)
- 大小: 不固定,通常是 8 字节、12 字节或 16 字节 (64/80/128 位)。
- 精度: 提供 至少和
double一样多,通常是 18-19 位或更多有效数字。 - 用途: 当需要比
double更高精度时使用,例如在高精度的科学计算或金融建模中。
类型大小和精度检查
你可以使用 C 语言的 sizeof 和 <float.h> 头文件中的宏来了解你当前系统上这些类型的具体信息。
#include <stdio.h>
#include <float.h> // 包含浮点数特性的宏
int main() {
printf("float 的存储大小: %lu 字节\n", sizeof(float));
printf("float 的最小正数: %E\n", FLT_MIN);
printf("float 的最大正数: %E\n", FLT_MAX);
printf("float 的精度 (小数位数): %d\n", FLT_DIG);
printf("\n");
printf("double 的存储大小: %lu 字节\n", sizeof(double));
printf("double 的最小正数: %E\n", DBL_MIN);
printf("double 的最大正数: %E\n", DBL_MAX);
printf("double 的精度 (小数位数): %d\n", DBL_DIG);
printf("\n");
printf("long double 的存储大小: %lu 字节\n", sizeof(long double));
printf("long double 的最小正数: %LE\n", LDBL_MIN);
printf("long double 的最大正数: %LE\n", LDBL_MAX);
printf("long double 的精度 (小数位数): %d\n", LDBL_DIG);
return 0;
}
注意: FLT_MAX 等宏的值会因平台(32位/64位)和编译器而异。
浮点数常量
在 C 语言中,如何书写一个浮点数常量?

- 十进制形式:
14,-0.5,.99, - 科学计数法 (E-notation):
14e2(表示 3.14 10² = 314),-1.5E-3(表示 -1.5 10⁻³ = -0.0015)
默认类型:
- 如果一个浮点数常量包含小数点 () 或指数部分 (
e或E),它的默认类型是double。 - 如果你想强制使用
float类型,可以在数字后面加上f或F后缀,14f。 - 如果你想强制使用
long double类型,可以在数字后面加上l或L后缀,14L。
float f = 3.14f; // f 是 float 类型 double d = 3.14; // d 是 double 类型 (默认) long double ld = 3.14L; // ld 是 long double 类型
浮点数变量声明与初始化
与整数变量类似,使用 float, double, long double 关键字来声明变量。
float pi = 3.14159f; double price = 19.99; long double large_number = 123456789012345.0L;
浮点数运算
浮点数可以使用标准的算术运算符:, , , 。
特别注意:

- 除法: 两个整数相除会得到整数结果(小数部分被丢弃),但只要操作数中有一个是浮点数,就会执行浮点数除法。
#include <stdio.h>
int main() {
int a = 5;
int b = 2;
float c = 5.0f;
float d = 2.0f;
// 整数除法,结果是小数部分被截断
int int_division = a / b;
printf("5 / 2 (整数) = %d\n", int_division); // 输出 2
// 浮点数除法
float float_division = c / d;
printf("5.0 / 2.0 (浮点) = %f\n", float_division); // 输出 2.500000
// 混合类型除法:整数和浮点数,结果会自动提升为浮点数
float mixed_division = a / d;
printf("5 / 2.0 (混合) = %f\n", mixed_division); // 输出 2.500000
return 0;
}
标准库函数
C 标准库 <math.h> 提供了丰富的数学函数来处理浮点数。
| 函数 | 描述 | 示例 |
|---|---|---|
sqrt(x) |
计算 x 的平方根 | sqrt(16.0) -> 0 |
pow(x, y) |
计算 x 的 y 次方 | pow(2.0, 3.0) -> 0 |
sin(x), cos(x), tan(x) |
三角函数 (x 为弧度) | sin(3.14159 / 2.0) -> ~1.0 |
log(x), log10(x) |
自然对数和常用对数 | log(10.0) -> ~2.302 |
fabs(x) |
计算 x 的绝对值 | fabs(-3.14) -> 14 |
ceil(x) |
向上取整 (不小于 x 的最小整数) | ceil(3.14) -> 0 |
floor(x) |
向下取整 (不大于 x 的最大整数) | floor(3.99) -> 0 |
#include <stdio.h>
#include <math.h> // 必须包含 math.h
int main() {
double num = 16.0;
double result = sqrt(num);
printf("The square root of %.2f is %.2f\n", num, result); // 输出 4.00
double angle = M_PI / 2; // M_PI 是 math.h 中定义的 π 值
printf("sin(PI/2) = %f\n", sin(angle)); // 输出 ~1.000000
return 0;
}
编译注意: 在 Linux/macOS 上使用 <math.h> 时,可能需要链接数学库,编译命令通常为 gcc your_program.c -o your_program -lm,在 Windows (如 MinGW) 中通常不需要。
关键问题:精度与误差
这是理解浮点数最重要的一点。
浮点数在计算机中不是精确存储的,而是用一种叫做 IEEE 754 的标准进行近似表示。 这会导致一些意想不到的结果。
问题 1: 精度有限
float 只有 6-7 位有效数字,如果你试图存储一个超过这个精度的数,它会被舍入。
float f = 123456789.0f;
printf("f = %.10f\n", f); // 可能输出 123456792.0000000000,最后几位不准确
问题 2: 误差累积
由于每次运算都可能引入微小的舍入误差,多次运算后误差会累积。
问题 3: 比较浮点数
永远不要使用 或 来精确比较两个浮点数是否相等! 因为微小的误差会导致比较失败。
正确的方法是使用一个很小的“容忍度”(epsilon)来判断两个浮点数是否“足够接近”。
#include <stdio.h>
#include <math.h>
// 判断两个浮点数是否“相等”
int are_floats_equal(double a, double b, double epsilon) {
// 如果差的绝对值小于一个极小的数,就认为它们相等
return fabs(a - b) < epsilon;
}
int main() {
double a = 0.1 + 0.2;
double b = 0.3;
// 错误的比较方式
if (a == b) {
printf("a 和 b 精确相等\n"); // 这行代码很可能不会执行
} else {
printf("a 和 b 不精确相等 (a=%.20f, b=%.20f)\n", a, b); // 会输出
}
// 正确的比较方式
double epsilon = 1e-9; // 一个很小的容忍度
if (are_floats_equal(a, b, epsilon)) {
printf("使用容忍度,a 和 b 被认为是相等的\n");
} else {
printf("使用容忍度,a 和 b 仍然不相等\n");
}
return 0;
}
输出示例:
a 和 b 不精确相等 (a=0.30000000000000004441, b=0.29999999999999998890)
使用容忍度,a 和 b 被认为是相等的
输入输出
使用 printf 和 scanf 来处理浮点数的输入输出。
| 格式说明符 | 类型 | 示例 |
|---|---|---|
%f |
float 或 double (默认6位小数) |
printf("%f", 3.14159); -> 141590 |
%lf |
double (用于 scanf 的 double 变量) |
scanf("%lf", &my_double); |
%Lf |
long double (用于 scanf 的 long double 变量) |
scanf("%Lf", &my_ldouble); |
%.2f |
保留2位小数 | printf("%.2f", 3.14159); -> 14 |
%e |
科学计数法 | printf("%e", 1234.56); -> 234560e+03 |
重要提示:
- 在
printf中,%f和%lf对于double类型变量效果是一样的。 - 在
scanf中,必须使用%lf来读取double类型的变量,如果你错误地使用%f,在 64 位系统上可能会导致未定义行为或读取错误,对于float,scanf使用%f;对于long double,使用%Lf。
#include <stdio.h>
int main() {
double d;
float f;
printf("请输入一个 double 类型的数字: ");
scanf("%lf", &d); // 正确:使用 %lf
printf("请输入一个 float 类型的数字: ");
scanf("%f", &f); // 正确:使用 %f
printf("你输入的 double 是: %.2f\n", d);
printf("你输入的 float 是: %.2f\n", f);
return 0;
}
| 特性 | 描述 |
|---|---|
| 类型 | float (低精度), double (高精度, 常用), long double (最高精度) |
| 常量 | 14f (float), 14 (double, 默认), 14L (long double) |
| 运算 | , , , ,注意混合类型运算时的自动类型提升。 |
| 库函数 | <math.h> 提供了 sqrt, pow, sin, fabs 等大量数学函数。 |
| 核心问题 | 精度有限和误差,不要用 比较浮点数,应使用容忍度方法。 |
| I/O | printf 用 %f/%e/%g,scanf 用 %lf (double) / %f (float) / %Lf (long double)。 |
