为什么我的“变更计算器”输出错误?

时间:2019-11-10 14:37:27

标签: c

我一直在做一个小小的爱好程序,该程序可以计算出一定数量的零钱。示例:

IN: ./program £5.50
OUT: £5 x 1
OUT: £0.50 x 1

但是,当处理某些以0.01或0.05结尾的数字时,代码会“跳过”它们或给出奇怪的结果,例如,不是给出£0.05 x 1,而是给出£0.02 x 2,然后跳过£0.01

代码如下:

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

#define NUMB_OF_CHANGE_AVAILABLE 12

float diff_change[NUMB_OF_CHANGE_AVAILABLE] = {
    50, 20, 10, 5,
    2, 1, 0.5, 0.2,
    0.1, 0.05, 0.02, 0.01} ;

void calc_change_needed(float total_amount) ;

int main(int argc, char const *argv[]) {
    float total_amount ;

    if (argv[1] == NULL)
    {
        printf("Please put number as first argument. Example:\n") ;
        printf("> ./program 5.55\n") ;
        return 0 ;
    } ;

    sscanf(argv[1], "%f", &total_amount) ;
    printf("Change number given: £%.2f\n", total_amount) ;
    calc_change_needed(total_amount) ;

    return 0;
} ;

void calc_change_needed(float total_amount)
{
    int i, multiples_needed ;
    float buffer_amount ;
    float amount_left = total_amount ;

    for (i = 0 ; i < NUMB_OF_CHANGE_AVAILABLE ; ++i)
    {
        multiples_needed = amount_left / diff_change[i] ;
        if (multiples_needed == 0) continue ;
        amount_left = amount_left - (multiples_needed * diff_change[i]) ;

        printf("£%.2f x %d\n", diff_change[i], multiples_needed) ;
    } ;

    if (amount_left == 0.01) printf("£0.01 x 1\n") ;
} ;

即使我写了应该给出0.01的输出(我希望最后一个被跳过),它仍然不会输出,即使 {{1 }} amount_left

我看过的一些例子并没有给出正确的输出:

0.01
IN: ./program 0.35
OUT: Change number given: £0.35
OUT: £0.20 x 1
OUT: £0.10 x 1
OUT: £0.02 x 2

尽管它确实适用于某些以0.01或0.05结尾的数字,例如:

IN: ./program 5.85
OUT: Change number given: £5.85
OUT: £5.00 x 1
OUT: £0.50 x 1
OUT: £0.20 x 1
OUT: £0.10 x 1
OUT: £0.02 x 2
IN: ./program 8.01
OUT: Change number given: £8.01
OUT: £5.00 x 1
OUT: £2.00 x 1
OUT: £1.00 x 1
OUT: £0.01 x 1

编辑:感谢所有评论,我意识到了问题所在。我现在要更改为只处理IN: ./program 8.06 OUT: Change number given: £8.06 OUT: £5.00 x 1 OUT: £2.00 x 1 OUT: £1.00 x 1 OUT: £0.05 x 1 OUT: £0.01 x 1 ,而不是int。我想我太固定了解决计算问题,而不是试图思考(小数点后的)想法本身是否错了。在以后的项目中将始终牢记这一点:) (尽管我不知道为什么这篇文章被低估了)

1 个答案:

答案 0 :(得分:1)

总体的主要问题是float肯定是像binary32这样的以2为基的浮点编码。这个金钱问题需要精确的数学运算来计算小数部分的值,例如0.01、0.05,而这些值不能在float中精确表示。切勿将float与金钱配合使用。

amount_left == 0.01使调查变得更加困难,floatdouble#include <math.h> ... double total_amount; sscanf(argv[1], "%lf", &total_amount) ; long long i_total_amount = llround(total_amount * 100.0); ... long i_change = lround(diff_change[i] * 100.0); // perform integer math with i_total_amount, i_change ... printf("£%.2f\n", i_total_amount/100.0); 的相等性进行比较-鉴于精度不匹配,几乎总是错误的。

相反,将输入和常量取为最小货币单位的整数,将内部数学运算为整数,然后根据需要打印出来。

Card