while循环不终止 - 浮点运算

时间:2014-06-20 13:53:40

标签: c while-loop floating-point

我正在使用浮点值处理C程序,下面是我的代码。

#include<stdio.h>
#include<stdlib.h>
#include<float.h>   

int main()
{
    int counter = 0;
    float quarter = 0.25;
    float dime = 0.10;
    float nickel = 0.05;
    float penny = 0.01;

    float change = 0.00;

    printf("hi, how much do i owe u?\t");
    scanf("%f", &change);

    while(change > 0.0)
    {
        if(change >= quarter)
        {
            change -= quarter;
            printf("quarter %.2f\n", quarter);
        }
        else if(change >= dime)
        {
            change -= dime;
            printf("dime %.2f\n", dime);
        }
        else if(change >= nickel)
        {
            change -= nickel;
            printf("nickel %.2f\n", nickel);
        }
        else if(change >= penny)
        {
            change -= penny;
            printf("penny %.2f\n", penny);
        }

        counter++;  
    }

    printf("your count is %i\n", counter);

    return 0;
}

输出是:

hi, how much do i owe u?    .45
quarter 0.25
dime 0.10
nickel 0.05
penny 0.01
penny 0.01
penny 0.01
penny 0.01
`^C`

我必须按ctrl c来终止循环

上次printf("your count is %i\n", counter);根本没有执行 - 使用<{1}}

如果我将count # of coins类型替换为float,则表示正常。

请帮助解决此问题

4 个答案:

答案 0 :(得分:3)

在循环开头添加:

if (change < penny) {
    printf("remaining: %.10f\n", change);
    break;
}

将发出此输出:

hi, how much do i owe u?        .45
quarter 0.25
dime 0.10
nickel 0.05
penny 0.01
penny 0.01
penny 0.01
penny 0.01
remaining: 0.0099999849
your count is 7

这是由内部浮点数表示引起的。存在固有错误 - 大多数浮点数没有精确的表示 - 它们只是非常好的近似值。

答案 1 :(得分:2)

帮自己一个大忙。取输入的值,乘以100,然后用全美分而不是美元进行所有计算。只有您的打印输出才能转换为美元和美分。

计算机使用整数比使用浮点数更准确。

答案 2 :(得分:0)

在循环结束时打印change,看看它最终会变成什么。我的猜测是,由于浮点错误,它将是一个非常小的正数。您只需将while语句更改为change > 1.e-3或其他较小的数字即可解决此问题。

答案 3 :(得分:0)

你的循环问题是没有一个案例可以匹配。我自己,我会写ifs链的最后一个分支为

else {
    /* must be the case that change >= penny */
    change -= penny;
    printf("penny %.2f\n", penny);
}

该评论解释了应该的情况,但如果不是这样,程序将不会失败。

如果由于某种原因你需要确定这个评论是真的(在这种情况下不是问题,但在更高风险的背景下可能是这样),你可以写

else {
    assert(change >= penny);
    change -= penny;
    ...
}

或者如果你想保留你所拥有的结构,你可以写

else if(change >= penny)
{
    change -= penny;
    printf("penny %.2f\n", penny);
} else {
    /* ooops! This should be impossible */
    fprintf(stderr, "Can't happen: change %f < penny\n", change);
    exit(1);
}

或类似的东西。通过一系列if语句,如果没有全部elseswitch without a默认值',您应该养成自动思考“如果不可能会发生什么会发生什么”的习惯em>发生吗?“

这是一个更大的问题(并且可能有点分散注意力),但使用断言进行编程是一个非常好的习惯。如果你能说服自己“X不可能是假的”(例如pointer != NULLi < i_max)那么把它写成断言。如果该断言是错误的,那么您立即在代码中发现了一个主要的逻辑错误。

最后一件事:为什么最后一次if测试失败了?在数学运算中,它不会失败,但要记住计算机使用浮点数,其中0.01不能精确表示。因此,表示为0.01(或0.05或0.10)的数字实际上不是那个数字,而是距离数字大约1e-7的数字,这意味着您拥有的change值将是只是< / em>低于0.01,或者只有高于0.0, 为什么change > 0.0都可以为真,change >= 0.01为假。