【问题标题】:Calculating smallest number of coins error计算最小硬币数量错误
【发布时间】:2015-08-24 12:34:06
【问题描述】:

我最近开始了 C 的在线课程,并且正在解决 PS1 中的第二个问题。这个问题要求我们要求用户输入以美元为单位的找零,并计算您可以给他们找零的最小硬币数量,前提是您只允许使用 25 美分、10 美分、5 美分和 1 美分的硬币。

例如,50 美分是 2 个 25 美分硬币,65 美分是 2 个 25 美分硬币、1 个 10 美分硬币和 1 个 5 美分硬币。

这是我的代码:

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

int main(void)
{
    float change = 0;
    int coinCounter = 0;
    int remainder = 0;
    int remainder1 = 0;
    int remainder2 = 0;
    int remainder3 = 0;
.
    do
    {
        printf("Please enter the change in dollars: ");
        change = GetFloat();
    }
    while(change <= 0);

    //converts amount in dollars to cents
    change = change*100;

    //We want to use the largest number of big cois as possible to make up the change.
    // This calculates the remainder (if any) after dividing the change by 25. % = modulo, only works with integer operands.
    remainder = (int)change % 25;

    //(change - remainder) gets us the largest number divisible by 25. This line then calculates 
    // the maximum number of 25cent coins we can use, and sets this number equal to the coinCounter.
    coinCounter = ((int)change - remainder)/25;

    //Finds the remainder (if any) when dividing the last remainder by 10.
    remainder1 = remainder % 10;

    //(remainder - remainder1) gets us the largest number divisible by 10. Dividing this by 10, we
    // determine the max amount of 10 cent coins we can use to make up the required change. We then add 
    // this number of coins to the total coinCounter.
    coinCounter = coinCounter + ((remainder - remainder1)/10);

    //Again, take the remainder (if any) from the last calculation, and find the remainder when dividing by 5.
    remainder2 = remainder1 % 5;

    // (remainder1 - remainder2)/5 tells us the number of 5 cent coins we need to make up the required change. 
    // We add the number of coins to the coin counter.
    coinCounter = coinCounter + ((remainder1 - remainder2)/5);

    //Finds the remainder when dividing last remainder by 1. There will actually be no remainder, so remainder 3 will
    // equal zero. 
    remainder3 = remainder2 % 1;

    //Here, (remainder2 - remainder1)/1 Finds the number of 1 cent coins required to make up the left change.
    // remainder3 will always be zero. Hence (remainder2)/1 will always be equal to remainder 2. We add this number
    // of 1 cent coins to the coinCounter.
    coinCounter = coinCounter + ((remainder2 - remainder3)/1);

    //We print out coinCounter, which is the smallest number of coins required to make up the change.
    printf("%i\n",coinCounter);
}

现在我是编程新手,所以我很清楚可能有更有效的方法来解决这个问题。但是,这似乎工作得很好。然而,奇怪的是,当我尝试“4.2”时,我得到了一个不正确的结果。我应该得到 18 个硬币(16 个 25 美分硬币和 2 个 10 美分硬币),但程序显示 22。它适用于我尝试过的所有其他数字。

我无法弄清楚我做错了什么。我觉得它要么与我通过乘以 100 将美元变为美分有关,要么与我计算模数并将变化转换为 int 有关,但不幸的是我无法单独计算出来。

我已经对我的代码进行了大量注释,因此它更容易理解。我希望有人可以帮助我!

【问题讨论】:

  • 哎呀,我想知道4.2是否不能在float中精确表示,floor(4.2f*100)不是420而是419。但不可能是原因,因为在stackoverflow上必须有数百个类似问题的答案......
  • 您可以使用更多printf调试单个段落或逐步执行;无论如何,你可以改进你的代码方法
  • 我不知道你当然知道,但你应该已经失败了,因为使用货币的浮点变量。整数转换只会让情况变得更糟。

标签: c cs50


【解决方案1】:

我会做一些更简单的事情,比如:

 int main(void)
{
    float change = 0;
    int coinCounter = 0;
    int remainder = 0;
    int remainder1 = 0;
    int remainder2 = 0;

do
{
    printf("Please enter the change in dollars: ");
    change = GetFloat();
}
while(change <= 0);

change = change*100;
coinCounter = (int)change/25; //number of 25cents
remainder = change % 25; //rest

if(remainder > 0){
     coinCounter += (int)remainder/10; //number of 10cts
     remainder1 = remainder%10;
}

if(remainder1 > 0){
     coinCounter += (int)remainder1/5; //number of 5cts
     remainder2 = remainder1%5
}

coinCounter += remainder2; //number of 1cts

printf("%i\n",coinCounter);   

}

4.2 是否解决了您的问题?我现在无法测试。

【讨论】:

  • 你好。感谢您的回复。此代码返回错误消息,因为模需要整数而不是浮点数。在“余数 = 更改 % 25;”行中我将更改转换为 int 并且代码运行了,但是仍然存在相同的问题。尝试 4.2 返回 22。
  • 好的,所以问题出在float 类型的change 变量上。也许如果您将change 类型设置为整数,然后执行change = (int)GetFloat()*100;,您将得到您想要的。
  • 谢谢,我已经使用 round() 函数解决了浮动问题。你的方法似乎更有效,所以我会研究它并尝试理解它。
  • @GettingTheHang-of-it 你在四舍五入什么?
  • change = round(change*100).. 所以它应该是 419.999,当我将它转换为 int 时,我相信它会是 419。在该计算中四舍五入解决了这个问题.
【解决方案2】:

问题是您将更改变量视为浮点数,而所有其他变量都是整数。

将 float 转换为 int 会引入一些不可预测的小错误,并且在某些情况下可能会失败。

如果你有兴趣有一篇很好的文章here.

我建议您将输入作为美分,或者如果不可能,则使用另一个整数变量并在程序开始时转换为美分,然后在计算中使用它。

【讨论】:

    【解决方案3】:

    正如 EOF 在他们的评论中(相当刻薄地)指出的那样,您遇到了浮点数的问题。浮点数并不完美,有很多(无限多)数字不能用 C 浮点数或双精度数精确表示。

    网上有很多关于这方面的好信息,for example here,但简短的解释是,在 C 中使用浮点数计算时,一些十进制值会给出错误的答案,而在您的特定编译器中,一个这样的数字是 4.2 * 100。

    在您的情况下,一种可能的解决方案是将浮点数转换为长整数,例如:

    change = change * 100 ;
    long value = change >= 0 ? (long)(change+0.5) : (long)(change-0.5) ;
    

    这应该会为您提供准确的美分数,并消除浮动计算中的小错误。

    顺便说一句,有时这些效果可能很难看到,请尝试打印以下结果:

    float x = 4.2 * 100 ;
    float y = 4.2 ;
    y = y * 100 ;
    

    在我的编译器中,这确实导致 x 为 420,但 y 为 419.99...。

    【讨论】:

    • 我不确定change &gt;= 0 的条件是否合理。为什么不round()?此外,float 不能表示的不仅仅是 无限 很多(实数)数字,而是 无数 无限多。
    • 感谢杰克逊的友好回复。我在 math.h 中使用了 round() 函数,它解决了我的问题。
    • 您可以为 change &gt;= 0.0F 争论以确定该数字是否为正,而 lroundf(float f) 直到 C99 才引入,并且原始发布者没有说明他们使用的是哪个版本以及无法代表的真实当我们到达可数和不可数的无限集时,我的头开始受伤......
    【解决方案4】:

    正如其他人所指出的,浮点值并不总是可以完美表示。要解决该错误,您可以四舍五入到最接近的整数。这是一个非常简单的函数:

    int round(float number)
    {
        return (number >= 0) ? (int)(number + 0.5) : (int)(number - 0.5);
    }
    

    像这样在你的代码中使用它:

    int main(void)
    {
        float change = 0;
        int changed = 0;
        int coinCounter = 0;
        int remainder = 0;
        int remainder1 = 0;
        int remainder2 = 0;
        int remainder3 = 0;
    
    do
    {
        printf("Please enter the change in dollars: ");
        change = GetFloat();
    }
    while(change <= 0);
    
    //converts amount in dollars to cents
    changed = round(change*100);//changes 419... to 420 etc.
    ...(more code)
    

    您必须尝试使用​​极端情况以使其适用于所有条件,但这将帮助您入门。

    注意:这个用于舍入的代码示例过于简化,只是为了帮助您入门。这个问题确实更复杂,正如 conversation 所示,处理将浮点数舍入到最接近的整数值。

    【讨论】:

    • 谢谢,这很有帮助。相反,我使用了 中的 round() 函数,但您的回复仍然很有用。
    • @GettingTheHang-of-it - 更好!我没有那个图书馆,所以不得不即兴创作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-09
    • 1970-01-01
    • 2021-03-04
    相关资源
    最近更新 更多