参考了这个题解
原本的思路是每一次都作除法,然后得到每种面额的钞票,但是忽略了 double 丢失精度的问题,这个最低有两位小数,两位小数的除法在面额 0.01 会丢失精度,较好的方法即视频中的方法,将总数乘 100,即将单位转换为分,这样就没小数了。
此外还有个错误,就是一开始怕小数除法会得到小数,就在前面加了个转 int,后来发现是多此一举,因为这个值是要赋值给 int 型的 int flag = (int)m/s[i]
;这样子反而还写错了,后面的除法也要括号起来,不然就是将 m 强转为 int 型来除以后面的 s[i] 了
设置了断点,因为数组里面浮点数肯定跟定义有出入,所以进行到这里时,a 已经是一个趋近于 0.01,但是要小一点的数,如果直接除以 0.01,那么得出来的就是 0,这时候就可以在后面加个类似 0.00001 这样的小数,帮助其到达 1,这样可以得到正确的答案。如果到这里的时候 a 是略大于 0.01 的,像 0.01000012 这样,除以p[6] 后再加上 0.0001 也不会影响,结果还是 1。因为 0.0001 对于整体的影响很小,但是由于精度的丢失,有的数据恰恰需要者 0.001。
原先的错误代码:
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
double m;
cin >> m;
int flag;
double s[12] = {100.00,50.00,20.00,10.00,5.00,2.00,1.00,0.50,0.25,0.10,0.05,0.01};
int n [12] = {0};
cout<< "NOTAS:" << endl;
for(int i=0; i<6; i++)
{
flag = (int)m/s[i];
printf("%d nota(s) de R$ %.2f\n",flag,s[i]);
m = m-flag* s[i];
}
cout << "MOEDAS:" << endl;
for(int i=6; i<12; i++)
{
flag = (int)m/s[i];
printf("%d moeda(s) de R$ %.2f\n",flag,s[i]);
m = m-flag* s[i];
}
return 0;
}
修改后的代码
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
double init;
cin >> init;
int m = init*100;
int flag;
double s[12] = {100.00,50.00,20.00,10.00,5.00,2.00,1.00,0.50,0.25,0.10,0.05,0.01};
int cent [12] = {10000,5000,2000,1000,500,200,100,50,25,10,5,1};
int n [12] = {0};
cout<< "NOTAS:" << endl;
for(int i=0; i<6; i++)
{
flag = m/cent[i];
printf("%d nota(s) de R$ %.2f\n",flag,s[i]);
m = m-flag* cent[i];
}
cout << "MOEDAS:" << endl;
for(int i=6; i<12; i++)
{
flag = m/cent[i];
printf("%d moeda(s) de R$ %.2f\n",flag,s[i]);
m = m-flag* cent[i];
}
return 0;
}