我一直在做一个小小的爱好程序,该程序可以计算出一定数量的零钱。示例:
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
。我想我太固定了解决计算问题,而不是试图思考(小数点后的)想法本身是否错了。在以后的项目中将始终牢记这一点:)
(尽管我不知道为什么这篇文章被低估了)
答案 0 :(得分:1)
总体的主要问题是float
肯定是像binary32这样的以2为基的浮点编码。这个金钱问题需要精确的数学运算来计算小数部分的值,例如0.01、0.05,而这些值不能在float
中精确表示。切勿将float
与金钱配合使用。
amount_left == 0.01
使调查变得更加困难,float
将double
与#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