在C语言嵌入式开发中,虽然我们通常推荐避免使用浮点数,但在实际操作中,特别是在维护他人代码时,往往需要处理浮点数。
浅浅的总结下用浮点数的介绍和使用注意事项:
一、C标准中的浮点类型
·C99标准中定义了float和double两种主要的浮点类型,用于表示单精度和双精度浮点数。
·C11标准进一步引入了long double类型,它提供了比double更高的精度和更大的数值范围。
·需要注意的是,这些浮点类型的具体实现可能会因编译器和平台的不同而有所差异。
二、软浮点与硬浮点的优缺点
· 硬浮点:依赖于处理器的硬件支持,具有专门的浮点运算单元(FPU)。其优点是处理速度快,但缺点是可移植性较差,依赖于具体的硬件实现。
·软浮点:在没有FPU的处理器上,通过软件库来模拟浮点运算。其优点是可移植性强,可以在多种硬件平台上运行,但缺点是处理速度相对较慢。
三、IEEE 754标准
· IEEE 754标准是国际上通用的浮点数表示和计算标准,旨在增加代码的可移植性。本文不对此标准进行详细讨论,
四、浮点数的不精确性
#include
int main() {
float a = 0.1;
float b = 0.2;
float result = a + b;
printf("0.1 + 0.2 = %.20f\n", result); // 输出可能为 0.30000001192092895508,而非预期的0.3
return 0;
}
·此示例展示了浮点数在表示和计算时的不精确性。由于二进制和十进制的转换问题,浮点数的运算结果可能与预期有所偏差。
五、使用分数进行精确运算
#include <stdio.h>
#include <stdlib.h>
#include <gmp.h>
int main() {
mpq_t a, b, result;
mpq_init(a);
mpq_init(b);
mpq_init(result);
mpq_set_str(a, "1/10", 10);
mpq_set_str(b, "1/5", 10);
mpq_add(result, a, b);
gmp_printf("1/10 + 1/5 = %Qd\n", result);
mpq_clear(a);
mpq_clear(b);
mpq_clear(result);
return 0;
}
为了进行精确的数学运算,可以使用GNU多精度算术库(GMP)中的分数类型。通过使用分数而非浮点数,可以确保运算结果的精确性。
六、避免使用"=="操作符比较浮点数
#include <stdio.h>
int main() {
float a = 0.1;
float b = 0.1 + 0.2;
if (a == b) {
printf("a equals b\n");
} else {
printf("a does not equal b\n");
}
return 0;
}
· 由于浮点数的不精确性,直接使用"=="操作符比较两个浮点数可能会导致错误的结果。在实际应用中,应该使用误差范围来比较浮点数,而不是直接比较。
七、避免将浮点数作为循环计数器
#include <stdio.h>
int main() {
float i;
for (i = 0.1; i < 1.0; i += 0.1) {
printf("%.1f\n", i);
}
return 0;
}
使用浮点数作为循环计数器可能会导致循环无法正确终止或产生意外的结果。在循环中,推荐使用整数作为计数器,以确保循环的可预测性和正确性。
八、在浮点运算中,整数需要转换为浮点数
#include <stdio.h>
int main() {
int a = 3;
float b = 0.5f; // 浮点数
float result;
// 这里会发生类型提升,整数a会被转换为浮点数,以便与b进行浮点运算
result = a / b;
printf("Result of integer division: %d\n", a / (int)b); // 直接的整数除法,结果为0
printf("Result of floating-point division: %f\n", result); // 浮点数除法,结果为6.000000
return 0;
}
当整数和浮点数参与混合运算时,整数会被隐式转换为浮点数,以执行浮点运算。这是因为浮点数提供了更大的表示范围和更高的精度,特别是对于小数部分的表示。
九、浮点数转换的范围检查
#include <stdio.h>
#include <limits.h>
int main() {
float a = INT_MAX;
if (a > INT_MAX) {
printf("Overflow occurred\n");
} else {
printf("No overflow occurred\n");
}
return 0;
}
在将整数转换为浮点数时,应进行范围检查,以确保转换后的结果在目标类型的合理范围内,避免发生溢出。