C程序整数浮点数运算异常:输入110 100未触发预期分支求助
问题原因及解决方案
你遇到的问题核心是二进制浮点数的精度限制 + 不同浮点类型转换的差异导致的边界判断失效:
- 1.1无法被二进制浮点数精确表示,double类型的1.1实际是一个略大于真实1.1的近似值;
- 当你用int类型的
limit_num(100)乘以double类型的1.1时,得到的结果是一个略大于110.0的double值(比如110.00000000000001); - 你把int类型的
speed(110)转成float后,在比较时会被自动提升为double类型,而110可以被float精确表示,所以提升后的结果是精确的110.0; - 此时比较
110.0 >= 110.00000000000001,结果为false,程序因此进入else分支输出OK。
下面是三种可行的解决方案:
方案一:用整数运算彻底避免浮点数精度问题
超速比例可以转化为整数乘法判断,完全规避浮点数的精度陷阱:
#include <stdio.h> int main() { int speed, limit_num; printf("please input :\n"); scanf("%d %d", &speed, &limit_num); // 用整数运算判断:150%即3/2,110%即11/10 if (speed >= limit_num * 3 / 2) { printf("Exceed %.0f%%. License Revoked\n", (double)(speed - limit_num)/limit_num * 100); } else if (speed >= limit_num * 11 / 10) { printf("Exceed %.0f%%. Ticket 200\n", (double)(speed - limit_num)/limit_num * 100); } else { printf("OK!\n"); } return 0; }
注意:如果limit_num数值极大,limit_num * 11可能会触发int溢出,可将变量改为long long类型避免。
方案二:统一使用float类型进行比较
将所有涉及比较的数值都转为float类型,避免double与float之间的类型转换差异:
#include <stdio.h> int main() { int speed, limit_num; printf("please input :\n"); scanf("%d %d", &speed, &limit_num); float speed_f = (float)speed; // 用float字面量1.1f,避免自动转为double float limit_110 = (float)limit_num * 1.1f; float limit_150 = (float)limit_num * 1.5f; if (speed_f >= limit_150) { printf("Exceed %.0f%%. License Revoked\n", (speed_f - limit_num)/limit_num * 100); } else if (speed_f >= limit_110) { printf("Exceed %.0f%%. Ticket 200\n", (speed_f - limit_num)/limit_num * 100); } else { printf("OK!\n"); } return 0; }
方案三:给浮点数比较添加误差容忍度
如果必须使用double类型比较,可以引入一个极小值(epsilon)来覆盖精度误差:
#include <stdio.h> #include <math.h> int main() { int speed, limit_num; printf("please input :\n"); scanf("%d %d", &speed, &limit_num); double speed_d = (double)speed; double limit_110 = (double)limit_num * 1.1; double limit_150 = (double)limit_num * 1.5; const double EPS = 1e-6; // 极小误差容忍值 if (speed_d >= limit_150) { printf("Exceed %.0f%%. License Revoked\n", (speed_d - limit_num)/limit_num * 100); } // 减去误差值,允许微小的精度偏差 else if (speed_d >= limit_110 - EPS) { printf("Exceed %.0f%%. Ticket 200\n", (speed_d - limit_num)/limit_num * 100); } else { printf("OK!\n"); } return 0; }
内容的提问来源于stack exchange,提问作者yeon hu
相关产品推荐
相关产品推荐

