当条件不满足时,while循环仍在执行的问题(C语言)

3

最近我正在学习计算机科学课程的一部分,学习了一点C语言。其中一个挑战是创建一个程序来告诉收银员需要多少硬币才能为客户找零。我用一组while循环完成了这个任务,整个程序看起来像这样:

#include <stdio.h>
#include <cs50.h>

int main(void)
{
    float f;
    int i;
    i=0;
do
{
    f = get_float("Input Change: \n");
}
while(f<0);
// This do-while loop uses a get_float operator to get a postive input from the user.
while(f>=0.25)
{
f=f-0.25;
i=i+1;
}
// Each one of these loops represents using one kind of coin. For this one, every time it runs it adds
// one coin to the final tally and removes 25 cents from the change owed.
while(f>=0.10)
{
f=f-0.10;
i=i+1;
}
// Dime loop, subtracts ten from change owed.
while(f>=0.05)
{
f=f-0.0500000;
i=i+1;
}
// Nickel loop, subtracts five from change owed.
while(f>0)
{
f=f-0.01;
i=i+1;
}
// Penny loop, subtracts one from change owed.
printf("You need %i coins.%f\n", i, f);
//This just prints the number of coins needed.
}

问题在于,即使没有理由执行最后一个while循环,我们仍然会随机执行它。例如,$0.42返回正确的值,而$0.15会导致最后一个while循环无缘无故地增加一分钱。
while(f>0)
{
f=f-0.01;
i=i+1;
}

(问题中有问题的 while 循环)

我对编程非常新手,所以这可能只是因为我做了一些傻事而导致的问题,但我不知道具体哪里出错了。有人之前遇到过这个问题吗?


1
首先,同样的输入是否总是产生相同的输出?其次,请尝试在每次迭代中打印f的值,我怀疑您可能存在浮点舍入误差。也许使用整数来表示整个美分会使数学计算更容易。 - Drew Reese
使用非标准C标头文件是一种糟糕的编程实践,这些文件不具备可移植性。如果您在一个课程中,则可以接受,但请记住,头文件cs50.h不具备可移植性。 - user3629249
一般来说,使用float类型表示货币值是非常危险的,因为float类型并不能保证百分之百正确的值。 - user3629249
为了更好的可读性和理解,请遵循以下编码规范:
  1. 请使用一致的缩进方式。在每个左大括号 '{' 之后,进行缩进;在每个右大括号 '}' 之前,取消缩进。建议每个缩进级别为四个空格。
  2. 使用单独的空行将 forifelsewhiledo...whileswitchcasedefault 代码块分隔开来。
- user3629249
2个回答

3

这是一个精度问题。使用浮点数进行相等比较可能会造成问题。即使在理论上,当你进入最后一个循环时,f=0,但实际上这种情况会失败并进入循环。

一个可能的解决方法是将其更改为介于00.01之间的某个数字。例如:

while(f>0.005)

但更好的方法是使用类型 int 来表示货币,每个单位对应一分钱。


1
使用浮点值进行比较时,与其他浮点数(例如5、0.63和0.0)相比会变得“奇怪”,因为您的值实际上可能是0.4999999999或0.000000000001,这基本上是零,在您的情况下未通过条件测试,因此在值真正变为负数时会添加最后一分钱。在比较浮点数时,必须通过将差异与某个小的epsilon值进行比较来解决这个问题。
float epsilon = 0.0000001;
if ((f - testVal) < epsilon) {
...
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接