虽然没有满足循环条件

时间:2014-08-16 16:49:03

标签: c if-statement while-loop floating-point greedy

我有这个功能:

int change(float c)
{
    float coins[] = {0.25, 0.10, 0.05, 0.01};
    int count[] = {0, 0, 0, 0};

    while(c > (0.00))
    {
        printf("I entered here\n");
        if((c-coins[0]) >= (0.00))
        {
            c -= coins[0];
            count[0]++;
            printf("-0.25, c = %.2f\n", c);
        }
        else if((c-coins[1]) >= (0.00))
        {
            c -= coins[1];
            count[1]++;
            printf("-0.10, c = %.2f\n", c);
        }
        else if((c-coins[2]) >= (0.00))
        {
            c -= coins[2];
            count[2]++;
            printf("-0.05, c = %.2f\n", c);
        }
        else if((c-coins[3]) >= (0.00))
        {
            c -= coins[3];
            count[3]++;
            printf("-0.01, c = %.2f\n", c);
        }
    }
    printf("(%d) 25 cents, (%d) 10 cents, (%d) 5 cents, (%d) 1 cents\n",
           count[0], count[1], count[2], count[3]);
    int total = count[0] + count[1] + count[2] + count[3];

    return total;
}

每当我尝试输入0.06或0.07,或任何导致它到达最后else if子句(else if((c-coins[3]) >= (0.00)))的浮点数时,它将导致无限循环。

然而,如果我输入0.25,0.10,0.05及其各自的完美倍数,则功能会顺利进行。 (因为它可能不会达到最后的else if条款。)

所以当我调试(使用简单的printf技术)时,我发现变量c 仍然进入while循环,即使它有达到0.00。在某些情况下,它甚至会达到-0.00或-0.01(这仅在我将else if((c-coins[3]) >= (0.00))更改为else时才有效。

示例(假设代码中的else if仅为else):
输入:0.06

c-0.05, c = 0.01
c-0.01, c = -0.00 **<- WTF** 
(0) 25 cents, (0) 10 cents, (1) 5 cents, (1) 1 cents
Total Coins: 2

有人向我解释这个吗?我错过了一些关于浮点数的规则吗?或者某些错误是由我的最后else if条引起的?

注意:将上一个else if更改为else可能会有效,但会影响最终答案。此外,将while条件更改为-0.000.001也不起作用。

1 个答案:

答案 0 :(得分:6)

浮点值(通常)使用二进制表示。 coins数组中唯一可以完全表示的部分是0.25。所有其他值将略小于或大于正确值。这意味着对这些值的每个算术运算,即使是简单的减法,都会引入小的计算错误,这会导致比较和输出出错。

在我看来,最好的解决方案是仅使用整数类型并以美分(数百)执行所有计算。您可以使用除法和模数打印出金额。

int change(int cents)
{
   int coins[] = {25, 10, 5, 1};
   int count[] = {0, 0, 0, 0};

   while(cents > 0)
   {
     if((c-coins[0]) >= 0)
     {
        c -= coins[0];
        count[0]++;
        printf("-0.25, c = %d.%02d\n", c/100, c%100);
     }
     /* and so on */

根据您的需要,您可能希望使用unsignedlong或两者。