简体   繁体   English

为什么while循环中的条件语句导致程序永远选择性地暂停?

[英]Why are the conditional statements in the while loop causing the program to pause selectively forever?

I am trying to figure out what the minimum number of coins required to pay back change is by using a "greedy algorithm". 我正在尝试通过使用“贪婪算法”来找出偿还找零所需的最小硬币数量。 The program I have written below is working as expected if the user enters a multiple of only one of the constant integers. 如果用户仅输入一个常数整数的倍数,我在下面编写的程序将按预期运行。 However, when it comes to to dealing with more than one coin, the program just pauses forever. 但是,当涉及处理多个硬币时,该程序将永远暂停。

I think that the problem is in my CountGreed function's while loop on the conditional statements. 我认为问题出在条件语句的CountGreed函数的while循环中。 I have tried finding answers but nothing I have come across seems to be giving me insight to guide me to understanding what the matter is with my logic. 我曾尝试寻找答案,但似乎没有发现任何启发我的见解,可以指导我理解我的逻辑所在。

I know this is trivial and there is repetition in the loop through the conditional statements which then brings me to the stated question. 我知道这是微不足道的,条件语句中的循环中有重复,然后将我带入所述问题。 Multiples of 0.25, 0.10, 0.05 and 0.01 are working well if entered by the user. 如果用户输入,则0.25、0.10、0.05和0.01的倍数效果很好。 For example, 1.00, 1.25, 0.20 but not 0.30, 1.13, 0.26, etc. 例如1.00、1.25、0.20,但不是0.30、1.13、0.26等。

#include "cs50.h" // Contains declaration for GetFloat()
#include <stdio.h>
#include <math.h>

float PromptChange(void); // Returns customer change in dollars
int ConvertToCents(float); // Returns a conversion from dollars to cents
int CountGreed(int); // Returns the minimum number of coins for which change can be made

int main (void)
{
    float Dollars = PromptChange();
    int Cents = ConvertToCents(Dollars);
    int CoinCount = CountGreed(Cents);
    printf("The minimum number of coins required to give back change is %i.\n", CoinCount);
    return 0;
}

float PromptChange(void)
{
    float Dollars;
    do {
        printf ("Owed change: $");
        Dollars = GetFloat ();
    } while (Dollars < 0);
    return Dollars;
}

int ConvertToCents(float Dollars)
{
    float Cents = Dollars * 100;
    int IntCents = (int)roundf(Cents);
    return IntCents;
}

int CountGreed(int IntCents)
{
    const int Quarter = 25, Dime = 10, Nickel = 5, Penny = 1;
    int SubCoinCount = 0;
    int CoinCount = 0;
    int Remainder = 0;
    while (IntCents) {
        if (IntCents >= Quarter) {
            SubCoinCount = IntCents / Quarter;
            CoinCount += SubCoinCount;
            Remainder += IntCents % Quarter;
            IntCents = Remainder;
        } else if (IntCents < Quarter && IntCents >= Dime) {
            SubCoinCount = IntCents / Dime;
            CoinCount += SubCoinCount;
            Remainder += IntCents % Dime;
            IntCents = Remainder;
        } else if (IntCents < Dime && IntCents >= Nickel) {
            SubCoinCount = IntCents / Nickel;
            CoinCount += SubCoinCount;
            Remainder += IntCents % Nickel;
            IntCents = Remainder;
        } else if (IntCents < Nickel && IntCents >= Penny) {
            SubCoinCount = IntCents / Nickel;
            CoinCount += SubCoinCount;
            Remainder += IntCents % Dime;
            IntCents = Remainder;
        }
    }
    return CoinCount;
}

I pasted the whole main.c file so that the flow of my entire program can be seen clearly though the problem is with the loop. 我粘贴了整个main.c文件,以便使整个程序的流程清晰可见,尽管问题出在循环中。 I have tried this on multiple compilers just to make sure that it is my fault. 为了确保这是我的错,我已经在多个编译器上进行了尝试。

This: 这个:

else if (IntCents < Nickel && IntCents >= Penny) {
    SubCoinCount = IntCents / Nickel;
    CoinCount += SubCoinCount;
    Remainder += IntCents % Dime;
    IntCents = Remainder;
}

should be this: 应该是这样的:

else if (IntCents < Nickel && IntCents >= Penny) {
    SubCoinCount = IntCents / Penny;   // <--- Change to Penny, or just remove
    CoinCount += SubCoinCount;
    Remainder += IntCents % Penny;     // <--- Change to Penny
    IntCents = Remainder;
}

Your four if cases are identical except for the denomination of the coin, which means they're crying out to be put into a separate function. 您的四个if壳除了硬币的面额相同外,这意味着它们渴望被用作单独的功能。 Doing that is a great way to avoid making errors like this in one or some of your cases, because you're only writing it once. 这样做是避免在一个或某些情况下发生此类错误的好方法,因为您只编写了一次。

I also suspect: 我也怀疑:

Remainder += IntCents % Dime;

should be: 应该:

Remainder = IntCents % Dime;

otherwise Remainder will increase endlessly, and IntCents will never get to zero. 否则, Remainder将无限增加,并且IntCents将永远不会为零。 Remainder actually becomes unnecessary, in this case, and you can assign the result directly to IntCents . 在这种情况下,实际上不需要Remainder ,您可以将结果直接分配给IntCents

But there's a simpler way of doing this entirely. 但是,有一种更简单的方法可以完全做到这一点。 Here's a suggested alternative, for your perusal: 这是一个建议的替代方法,供您仔细阅读:

#include <stdio.h>

//  This cries out to be its own function

int coin_count(int cents, int denomination, int * remainder)
{
    *remainder = cents % denomination;
    return cents / denomination;
}

//  Better way

int CountGreed(int IntCents)
{
    static const int Quarter = 25, Dime = 10, Nickel = 5, Penny = 1;
    int CoinCount = 0;

    while ( IntCents > 0 ) {
        if ( IntCents >= Quarter ) {
            CoinCount += coin_count(IntCents, Quarter, &IntCents);
        } else if ( IntCents >= Dime ) {
            CoinCount += coin_count(IntCents, Dime, &IntCents);
        } else if ( IntCents >= Nickel ) {
            CoinCount += coin_count(IntCents, Nickel, &IntCents);
        } else if ( IntCents >= Penny ) {
            CoinCount += coin_count(IntCents, Penny, &IntCents);
        }
    }

    return CoinCount;
}

//  Even better way

int CountGreed2(int IntCents)
{
    static const int coins[4] = {25, 10, 5, 1};
    int CoinCount = 0;

    for ( int i = 0; i < 4; ++i ) {
        if ( IntCents >= coins[i] ) {
            CoinCount += coin_count(IntCents, coins[i], &IntCents);
        }
    }

    return CoinCount;
}

int main(void) {
    printf("Coins for $1.25 (should be 5): (%d)\n", CountGreed(125));
    printf("Coins for $1.00 (should be 4): (%d)\n", CountGreed(100));
    printf("Coins for $0.96 (should be 6): (%d)\n", CountGreed(96));

    printf("Coins for $1.25 (should be 5): (%d)\n", CountGreed2(125));
    printf("Coins for $1.00 (should be 4): (%d)\n", CountGreed2(100));
    printf("Coins for $0.96 (should be 6): (%d)\n", CountGreed2(96));

    return 0; 
}

which outputs: 输出:

paul@local:~/Documents/src/sandbox$ ./coins
Coins for $1.25 (should be 5): (5)
Coins for $1.00 (should be 4): (4)
Coins for $0.96 (should be 6): (6)
Coins for $1.25 (should be 5): (5)
Coins for $1.00 (should be 4): (4)
Coins for $0.96 (should be 6): (6)
paul@local:~/Documents/src/sandbox$ 

The need for a separate function in CountGreed2() is less obvious, since you're only writing it once anyway, but tastes vary. CountGreed2()对单独功能的CountGreed2()不太明显,因为无论如何您只编写一次,但是口味各不相同。

#include "cs50.h" // Contains declaration for GetFloat()
#include <stdio.h>
#include <math.h>

float PromptChange(void); // Returns customer change in dollars
int ConvertToCents(float); // Returns a conversion from dollars to cents
int CountGreed(int); // Returns the minimum number of coins for which change can be made

int main (void)
{
    float Dollars = PromptChange();
    int Cents = ConvertToCents(Dollars);
    int CoinCount = CountGreed(Cents);
    printf("The minimum number of coins required to give back change is %d.\n",
           CoinCount);
    return 0;
}

float PromptChange(void)
{
    float Dollars;
    do {
        printf ("Owed change: $");
        Dollars = GetFloat ();
    } while (Dollars < 0);

    return Dollars;
}

// the original function ConvertToCents() 
// will usually return an incorrect value
// typically off by 1
// This is because float values often cannot exactly represent
// the desired value
int ConvertToCents(float Dollars)
{
    float Cents = Dollars * 100.0f; // note all values should be float
    int IntCents = floor(Cents+.5f); // round up to whole penny

    return IntCents;
}

int CountGreed(int IntCents)
{
    const int Quarter = 25, Dime = 10, Nickel = 5, Penny = 1;
    int CoinCount = 0;
    int Remainder = IntCents; // get working value

    // note following using integer divides
    CoinCount = Remainder / Quarter; // max quarters
    Remainder = Remainder % Quarter; // update working value

    CoinCount += Remainder / Dime;   // max dimes
    Remainder = Remainder % Dime;    // update working value

    CoinCount += Remainder / Nickle; // max nickles
    Remainder = Remainder % Nickle;  // update working value

    CoinCount += Remainder;          // final pennys

    return CoinCount;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM