如何不修改测试用例使C语言浮点转换测试全部通过?
解决浮点数相等判断导致的测试用例失败问题
我写了一段用指针实现磅转千克的C语言代码,做了两个测试用例:一个拿函数输出和宏对比,测试通过;另一个拿函数输出和等于该宏的变量对比,测试失败。我知道浮点数用==判断可能返回false,也了解浮点数运算的精度问题,但作业要求不能修改测试用例,不知道怎么解决。测试过lbs == TEST_LBS是true的,用gcc编译运行,命令是gcc -Wall test.c -o test和./test.exe。
代码实现
#define TEST_LBS 5.5 #define CONVERSION_FACTOR 2.20462 #include <stdio.h> void testConvertLbsKg(void); double convertLbsKg(double *weightLbsPtr, double *weightKilosPtr); int main() { testConvertLbsKg(); return 0; } void testConvertLbsKg(void) { double dblA, dblB, lbs = TEST_LBS; dblA = dblB = 0.0; printf("Test-1: \n"); dblB = convertLbsKg(&lbs, &dblA); if (dblA == dblB && dblA == TEST_LBS / CONVERSION_FACTOR) printf("<PASSED> with macro\n"); else printf("<!!! FAILED with macro!!!>\n"); if (dblA == dblB && dblA == lbs / CONVERSION_FACTOR) printf("<PASSED> with variable\n"); else printf("<!!! FAILED with variable!!!>\n"); } double convertLbsKg(double *weightLbsPtr, double *weightKilosPtr) { double result; result = *weightLbsPtr / CONVERSION_FACTOR; if (weightKilosPtr != NULL) { *weightKilosPtr = result; } return result; }
程序输出
Test-1: <PASSED> with macro <!!! FAILED with variable!!!>
问题根源
问题出在编译期常量计算和运行期变量计算的浮点数精度差异:
- 宏表达式
TEST_LBS / CONVERSION_FACTOR是编译阶段直接计算的,编译器会用更高精度的内部计算(比如long double)得到结果后,再转换为double类型存储到程序中。 - 而
lbs / CONVERSION_FACTOR是运行阶段计算的,lbs是double类型变量,除以同样是double类型的2.20462,但由于2.20462无法被double精确表示,运行时的浮点运算路径和编译期的高精度计算路径会产生极细微的精度偏差,导致两个结果用==对比时返回false。
不修改测试用例的解决方法
方法1:修改宏定义为精确的double表示
由于2.20462无法被double精确存储,编译器在编译期和运行期使用的2.20462实际是两个略有差异的近似值。我们可以先获取2.20462对应的精确double值,再修改宏定义:
- 运行以下代码获取精确值:
#include <stdio.h> int main() { double x = 2.20462; printf("%.20lf\n", x); return 0; } - 将输出的精确值替换原
CONVERSION_FACTOR的宏定义,比如输出是2.2046199999999998,则修改为:#define CONVERSION_FACTOR 2.2046199999999998
这样编译期和运行期使用的是同一个精确的double值,两次计算的结果完全一致,两个测试用例都会通过。
方法2:启用编译器优化
使用-O1及以上的优化级别编译代码,编译器会识别到lbs是初始化为TEST_LBS且从未修改的变量,将lbs / CONVERSION_FACTOR优化为编译期常量,和TEST_LBS / CONVERSION_FACTOR的结果一致:
gcc -Wall -O1 test.c -o test ./test.exe
内容的提问来源于stack exchange,提问作者R.Bansal
相关产品推荐
相关产品推荐

