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

int main(void) {

    printf("Enter your change: ");
    int pennies = 0, nickels = 0, dimes = 0, quarters = 0;
    float change = GetFloat();

    while (change > 0) {
        if (change >= 0.25) {
            quarters++;
            change -= 0.25;
        }
        else if (change >= 0.10) {
            dimes++;
            change -= 0.10;
        }
        else if (change >= 0.05) {
            nickels++;
            change -= 0.05;
        }
        else if (change >=0.01) {
            pennies++;
            change -= 0.01;
        }
        // force break
        else {
        printf("%1.2f - Num. of change left\n", change);
        break;
        }
    }
    printf("Quarters: %d\n", quarters);
    printf("Dimes: %d\n", dimes);
    printf("Nickels: %d\n", nickels);
    printf("Pennies: %d\n", pennies);
    return 0;
}

您好,我目前是 C 的新手,我正在在线上哈佛的 CS50 课程。“更改”变量似乎下降到 0.00 而没有停止 while 循环。这迫使我在最后输入“break”。我的代码有什么问题?

顺便说一下,这是来自问题集 1。

4

6 回答 6

6

浮点数在计算机内存中的表示方式存在问题。简而言之:并非所有数字都可以精确存储。请阅读此页面了解更多详情:http ://en.wikipedia.org/wiki/Floating_point#Accuracy_problems

您可以使用此服务检查计算机中浮点数的表示:http: //www.binaryconvert.com/result_float.html

关于您的情况,假设您输入了 0.4。这意味着它应该被分成 0.25 + 0.1 + 0.05。并且change应该为零,但是:

0.40 == 0.4000000059604644775390625000,
 minus
0.25 == 0.2500000000000000000000000000 (exact),
 minus
0.10 == 0.1000000014901161193847656250,
 minus
0.05 == 0.0500000007450580596923828125
 is
0.00 == 0.0000000037252902984619140625

如您所见,最终结果略高于零,这会阻止您的循环结束。

一般来说,如果你需要数钱,你应该使用int来数“分”。或自定义类型。或长算术。或者其他什么,但不是浮点数,因为大多数国家的货币在一个点之后只需要两个位置,因此这个点不需要浮动

于 2013-06-22T16:47:06.943 回答
1

您不应该使用浮点数来表示本质上是整数的数字。浮点运算在这里是一个问题。Change在大多数情况下永远不会等于 0。你应该只用整数做所有事情,它会起作用。算法看起来不错。

http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

http://floating-point-gui.de/

于 2013-06-22T15:57:59.890 回答
1

正如其他人所说,这是一个浮点问题。这是你的问题:

else if (change >=0.01) {
            pennies++;
            change -= 0.01;
        }

可能发生的情况是它change最终比 0.01 略高,所以当你从中减去 0.01 时,它最终会略大于零,但小于 0.01,并且你没有if处理这种可能性的子句,所以它继续下去永远。你的printf()显示为零,因为你将它四舍五入到小数点后两位,所以它看起来像 0.00,即使它可能是 0.00001 或其他东西。

于 2013-06-22T16:28:43.303 回答
1

使用浮点数是不明智的,正如这里多次说明的那样......

但从逻辑上讲,你可以做你正在尝试的事情,我怀疑它与 C 中的比较和提升规则有关......但我想这会解决你的问题:

while (change > 0.0f)

这样你就可以比较类似的类型......

实际上,您应该更改为使用 int、long 或 long long... 并代表美分而不是美元。

于 2013-06-22T16:38:55.087 回答
1

未经测试,但这是我写它的方式。它使用int而不是float避免舍入问题,对每个硬币都有一个表格驱动的计算,并且进行除法而不是重复减法。

int change = GetFloat() * 100 + 0.5;
struct {const char *name; int value;} coins[] = {
    {"Quarters", 25},
    {"Dimes", 10},
    {"Nickels", 5},
    {"Pennies", 1},
};
for (int i = 0; i < 4; i++) {
    int coin = change / coins[i].value;
    change %= coins[i].value;
    printf("%s: %d\n", coins[i].name, coin);
}
于 2013-06-22T17:33:49.023 回答
0

您应该使用与 getFloat() 等效的整数,或使用整数变量进行比较。由于浮点问题,代码出错了。

    #include<math.h>  // for round
...
...
    int change = int)100 * round(getFloat());
于 2013-06-22T15:53:04.243 回答