【问题标题】:C while-loop not stoppingC while循环没有停止
【发布时间】:2013-06-22 15:50:06
【问题描述】:
#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。

【问题讨论】:

标签: c while-loop cs50


【解决方案1】:

浮点数在计算机内存中的表示方式存在问题。简而言之:并非所有数字都可以精确存储。请阅读此页面了解更多详情: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来数“美分”。或自定义类型。或长算术。或者其他什么,但不是浮点数,因为大多数国家的货币在一个点之后只需要两个位置,因此这个点不需要浮动

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

        【解决方案4】:

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

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

        while (change > 0.0f)
        

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

        你真的应该改用 int、long 或 long long... 并表示美分而不是美元。

        【讨论】:

        • 我想这只有在事实上你有足够的能力得到小于零的情况下才会起作用。
        【解决方案5】:

        未经测试,但这是我写它的方式。它使用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);
        }
        

        【讨论】:

          【解决方案6】:

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

              #include<math.h>  // for round
          ...
          ...
              int change = int)100 * round(getFloat());
          

          【讨论】:

          • 他希望将其乘以 100,然后四舍五入并转换为 int...
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-09-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多