整数溢出贪婪的硬币计数

时间:2016-11-23 12:55:59

标签: c greedy cs50

int A[]={};

我正在尝试实施一个小贪婪算法,其中用户输入一定数量的钱(例如:9.25),我们输出最少量的硬币,我们需要更换它(25美分,仅10美分,5美分和1美分。)

此算法适用于10或20之类的int金额,其金额仅需要程序使用25美分硬币。

如果我尝试9.10或9.01之类的数量,我会收到运行时错误,有符号整数溢出。我理解这意味着什么,但我不明白硬币的价值怎么会突然变得如此之高。

6 个答案:

答案 0 :(得分:3)

正如Danial Tran所说,在进行逻辑运算时最好使用int。请阅读Why not use Double or Float to represent currency?您也可以避免循环播放。

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

int main (void) { 

    printf ("Enter amount: ");
    //float amount = GetFloat(); //Please refer to chqrlie's comments below.
    double amount  = 0.0;
    scanf("%lf",&amount); //I don't know GetFloat() equivalent for double. So using scanf().

    long long int amountInt = (long long int) (amount * 100.0);

    int coins = 0;

    if (25 <= amountInt) {
        coins += (amountInt/25);
        amountInt = amountInt % 25;
    }

    if (10 <= amountInt) {
        coins += (amountInt/10);
        amountInt = amountInt % 10;
    }

    if (5 <= amountInt) {
        coins += (amountInt/5);
        amountInt = amountInt % 5;
    }

    if (1 <= amountInt) {
        coins += amountInt;
    }

    printf ("Coins : %d\n", coins);
}

答案 1 :(得分:1)

您的算法不正确:

例如30美分你可以用你的算法交换到:25 + 5(2个硬币)它将是10 + 10 + 10(3个硬币)。如此贪婪意味着为什么它超过25美分然后先换成25美分。

while (amount != 0) {

    if (amount >= 0.25) {
        amount = amount - 0.25;
        coins += 1;
    }

    else if (amount >= 0.10) {
        amount = amount - 0.10;
        coins += 1;
    }

    else if (amount >= 0.05) {
        amount = amount - 0.05;
        coins += 1;
    }

    else {
        amount = amount - 0.01;
        coins += 1;
    }
}

如果你想这样做。

更好的方式:

int coinTypes[] = {0.25, 0.1, 0.05, 0.01};

for (int i = 0; i < 4; i++) {
   coins += floor(amount / coinTypes[i];
   amount -= coins * coinsTypes[i];
}

答案 2 :(得分:1)

似乎没有人回答过这个问题

  

如果我尝试9.10或9.01之类的数量,我会收到运行时错误,签名整数溢出,我明白这意味着什么,但我不明白硬币的价值怎么会突然变得如此之高。 / p>

所以为了完整起见,部分作为练习:

您可以使用调试器找到原因。我复制了你的代码,发现它运行了很长时间。在启动后中断一下,发现代码冻结了重复此检查:

if (fmod(amount, 0.25) == 0) {
    amount = amount - 0.25;
    coins += 1;
}

在中断的那一刻amount约为120万,硬币差不多有500万。这清楚地表明了你未能检查的一件事:消极性。你可以轻松地使用你错过了 exact 零的浮点数,因为其他人已经正确推理,不需要重复。但是如果发生这种情况,你的程序应该在amount变为负面时感到担忧。否则,在正确的条件下,它也可以继续减去负向无穷大的方式,是的,整数溢出将发生在coins

答案 3 :(得分:1)

这是因为计算机代表二进制(幂为2)的小数

对于0.25,计算机可以用二进制表示它。这是因为我们可以使用2 的幂来获得0.25。

然而,对于0.10(或其他提及的面额),它们不能用2的幂表示。

假设你试图使用2的幂来获得0.1,你将无法准确地获得它。你可以靠近它。

0.1 = 0.0625(2 ^ 4)+ 0.03125(2 ^ 5)+ 0.00390625(2 ^ -8)+ ...

你将接近0.1,但你永远不会达到0.1。

Float,double每个人都有一个固定的位数来表示小数。所以它只保留那么多位,其总和将略小于0.1

如果您想采用相同的方法,您可以有两种可能的解决方案: -

  
      
  1. 使用(金额> 0)代替(金额!= 0),或
  2.   
  3. 使用可以在 2的幂中轻松表达的货币,例如0.25,0.125,0.375,0.06125。
  4.   

答案 4 :(得分:0)

您的算法的主要问题是无效使用fmod函数。根据定义,fmod(num, denom)的结果是

fmod = num - floor(num/denom) * denom

其中floor(num/denom)是整数。 因此,fmod(9.10, 0.25) == 0.1fmod(9.10, 0.10) == 0.1

此外,使用浮点数的操作很少给出精确的结果。所以amount永远不会0

答案 5 :(得分:0)

您无法使用float类型进行计算。不是0.25的精确倍数的金额无法在floatdouble类型中准确表示。

您可以通过计算精确的分数并使用整数算术分发来解决此问题:

#include <stdio.h>
#include <math.h>

void print_coins(int coins, const char *singular, const char *plural) {
    if (coins > 0)
        printf(" %d %s", coins, coins > 1 ? plural : singular);
}

int main(void) {
    for (;;) {
        double amount;
        int amountInt, coins, quarters, dimes, nickels, pennies;

        printf("Enter amount: ");
        if (scanf("%lf", &amount) != 1 || amount <= 0)
            break;

        amountInt = (int)(amount * 100.0 + 0.5);

        quarters = amountInt / 25;
        amountInt %= 25;
        dimes = amountInt / 10;
        amountInt %= 10;
        nickels = amountInt / 5;
        amountInt %= 5;
        pennies = amountInt;
        amountInt = 0;

        coins = quarters + dimes + nickels + pennies;

        printf("coins returned: %d:", coins);
        print_coins(quarters, "quarter", "quarters");
        print_coins(dimes, "dime", "dimes");
        print_coins(nickels, "nickel", "nickels");
        print_coins(pennies, "penny", "pennies");
        printf("\n");
    }
    return 0;
}

注意:

  • 在没有float的情况下使用+ 0.5,更改不正确,只需{1}}:一分钱短。
  • 使用100.10float的更改不正确:3个额外的便士。
  • 要处理超过2000万美元的金额,您需要更大的整数类型,例如1000000.10。这样,您就可以处理超过美国国债的金额。