while循环不终止 – 浮点运算
我正在使用浮点值处理C程序,下面是我的代码。
#include #include #include int main() { int counter = 0; float quarter = 0.25; float dime = 0.10; float nickel = 0.05; float penny = 0.01; float change = 0.00; printf("hi, how much do i owe u?\t"); scanf("%f", &change); while(change > 0.0) { if(change >= quarter) { change -= quarter; printf("quarter %.2f\n", quarter); } else if(change >= dime) { change -= dime; printf("dime %.2f\n", dime); } else if(change >= nickel) { change -= nickel; printf("nickel %.2f\n", nickel); } else if(change >= penny) { change -= penny; printf("penny %.2f\n", penny); } counter++; } printf("your count is %i\n", counter); return 0; }
输出是:
hi, how much do i owe u? .45 quarter 0.25 dime 0.10 nickel 0.05 penny 0.01 penny 0.01 penny 0.01 penny 0.01 `^C`
我必须按ctrl
c
才能终止循环
最后的printf("your count is %i\n", counter);
根本不执行 – count # of coins
使用count # of coins
如果我用int
替换float
类型,它可以正常工作。
请帮助解决这个问题
在循环开始时添加:
if (change < penny) { printf("remaining: %.10f\n", change); break; }
将发出此输出:
hi, how much do i owe u? .45 quarter 0.25 dime 0.10 nickel 0.05 penny 0.01 penny 0.01 penny 0.01 penny 0.01 remaining: 0.0099999849 your count is 7
这是由内部浮点数表示引起的。 有一个固有的错误 - 大多数浮点数没有精确的表示 - 它们只是非常好的近似值。
做一个巨大的帮助。 取输入的值,乘以100,然后以美分而不是美元计算所有计算。 只有您的打印输出才能转换为美元和美分。
计算机使用整数比使用浮点数更准确。
在循环结束时打印出change
,并查看最终的变化。 我的猜测是,由于浮点错误,它将是一个非常小的正数。 您可以通过简单地将while
语句change > 1.e-3
为change > 1.e-3
或其他更小的数字来解决此问题。
你的循环的问题是没有一个案例可以匹配。 我自己,我会写ifs链的最后一个分支
else { /* must be the case that change >= penny */ change -= penny; printf("penny %.2f\n", penny); }
评论解释了这里应该是什么情况,但如果不是这样,程序将不会失败。
如果由于某种原因你需要确定这个评论是真的(在这种情况下不是问题,但在更高风险的情况下可能是这样),你可能会写
else { assert(change >= penny); change -= penny; ... }
或者如果你想保留你所拥有的结构,你可以写
else if(change >= penny) { change -= penny; printf("penny %.2f\n", penny); } else { /* ooops! This should be impossible */ fprintf(stderr, "Can't happen: change %f < penny\n", change); exit(1); }
或类似的东西。 if
有一系列if
语句没有else
所有的else
,或者switch without a
默认的switch without a
,你应该养成自动思考“如果不可能发生会怎么样?”的习惯。
这是一个更大的问题(并且可能有点分散注意力),但使用断言进行编程是一个非常好的习惯。 如果你能说服自己“X不可能是假的”(比如pointer != NULL
,或者i < i_max
)那么把它写成断言。 如果该断言是错误的,那么您立即在代码中发现了一个主要的逻辑错误。
最后一件事: if
测试失败, 为什么这是最后一次? 在数学运算中,它不会失败,但要记住计算机使用浮点数,其中0.01不能精确表示。 因此,表示为0.01(或0.05或0.10)的数字实际上不是那个数字,而是距离数字大约1e-7的数字,这意味着您所具有的change
值将低于0.01或略高于0.0, 这就是为什么change > 0.0
都可以为真,并且change >= 0.01
false。