【问题标题】:cash division error in C with floating points带有浮点的C中的现金除法错误
【发布时间】:2019-05-14 12:17:03
【问题描述】:

我目前正在研究 cs50“现金”问题:估计支付一些零钱所需的硬币数量。

例如:欠款 0.41 美元 = 1 美分硬币、1 美分硬币、1 美分、1 便士。

但是,在估算所需硬币的数量时,我最终会失去几分钱,我认为这是由于我的错误,因为它似乎总是少了一两个硬币(便士)。

我已经包含了多个 printf 语句来尝试跟踪我可以做的事情,但我似乎无法弄清楚为什么该部门不起作用。

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

int main(void)
{
    // change
    float change = get_float("how much change is owed?: ");
    int coins = 0;

    //reprompt
    while (change < 0)
    {
        change = get_float("how much change is owed?: ");
    }

    //quarter
    float quarter = 0.25;
    float quarters = change / quarter;
    quarters = (int) quarters;
    change = change - (quarters * quarter);

    printf("%f quarters\n", quarters);

    //dimes
    float dime = 0.10;
    float dimes = change / dime;
    dimes = (int) dimes;
    change = change - (dimes * dime);

    printf("%f dimes\n", dimes);

    //nickels
    float nickel = 0.05;
    float nickels = change / nickel;
    nickels = (int) nickels;
    change = change - (nickels * nickel);

    printf("%f nickels\n", nickels);
    printf("%f in change left change\n", change);

    //pennies
    float penny = 0.010000;
    float pennies = change / penny;
    pennies = (int) pennies;
    change = change - (pennies * penny);

    printf("%f pennies\n", pennies);

    //coins
    coins = quarters + dimes + nickels + pennies;
    printf("%i\n", coins);

    //printf("%f\n", change);
}

【问题讨论】:

  • 你试过检查CS50吗?
  • 是的,但是他们内置的帮助功能无法帮助我。
  • 您可能遇到了这个问题:(int)0.99999 == 0。浮点运算非常棘手。您可以通过仅使用整数运算来解决它(以便士为基本单位)。
  • 我建议不要使用 float 来完成这项任务。只需使用int 来跟踪便士的数量。所以一角钱不会是0.1,而是10,等等。
  • 您的printf 语句未能显示正确的值。 %f 将值四舍五入到小数点后六位。要显示完整的值%.99g 对于这些情况就足够了,如果您的 C 实现格式正确,%a 将使用十六进制浮点格式显示确切的值。

标签: c floating-point int division cs50


【解决方案1】:

在您的 C 实现中,这些行:

float dime = 0.10;
float nickel = 0.05;
float penny = 0.010000;

dime 设置为 0.100000001490116119384765625,将nickel 设置为 0.0500000007450580596923828125,将 penny 设置为 0.009999999287648258.258.这导致每个硬币的计算略有偏差。此外,change在处理每个硬币后的计算存在舍入误差。

要解决此问题,在使用 get_float 获取 change 后,将其转换为美分数:

int cents = roundf(change * 100);

然后使用整数算术执行所有计算。 (包含&lt;math.h&gt; 获取roundf 的声明。)

【讨论】:

    【解决方案2】:

    从这一行开始:

    #include <math.h>
    
    
    #define PENNIES_IN_GBP (100)
    
    
    int main(void)
    {
            int change_pn = roundf(PENNIES_IN_GBP * get_float("how much change is owed?: "));
    
            /* ... */
    
            return 0;
    }
    

    剩下的应该很容易;)

    【讨论】:

    • roundf 将舍入为整数美元,损失美分。
    【解决方案3】:

    只是一个建议,为什么不以整数算术执行所有计算?将浮点“零钱”转换为整数“美分”

    (int) cents = roundf(100.0 * change); // see comments below answer
    

    然后将之后的所有内容都保留为整数,例如

    //quarter
    const int quarter = 25;
    int quarter_count = cents / quarter;
    cents = cents % quarter; // use modulus operator
    

    我还恭敬地建议使用非常相似的变量名称,例如季度和季度,可能会导致错误。

    由于您永远不想更改一个季度的美分数(尤其是意外),您可以将其声明为 const int。

    您可能还想检查用户是否输入了他们认为是美元的小数(浮动)金额,而不是整数美分。但这超出了这个问题的范围。

    【讨论】:

    • (int) (100.0 * change); 有问题,因为change 可能小于所需值。例如,如果用户输入“.41”,change 将是 40.99999964237213134765625,100.0 * change 将是 40.99999964237213134765625,导致 cents 是 40,而应该是 41。
    • @Eric Postpischil - 很公平。它应该是 (int) (100.0 * (change +0.5));,对于 41 +/- 0.5 以内的任何 change 值,它将舍入到 41
    • 对于“.41”的输入,(int) (100.0 * (change +0.5)) 产生 90。您需要100 * change + .5。但是没有必要拼凑你自己的舍入函数。 &lt;math.h&gt; 库具有用于此目的的函数,例如 roundflroundf
    • 好的,Eric,点了。自从我愤怒地写C以来已经有很长时间了,我已经忘记了那些功能。这就是我们在引入round 之前的做法(我相信是 1999 年)。无论如何,我回答的要点是最好用整数算术进行计算,避免浮点到整数转换和舍入错误的所有陷阱。连我都掉进去了!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-21
    • 1970-01-01
    • 2018-08-27
    相关资源
    最近更新 更多