题目描述
读取一个带有两个小数位的浮点数,这代表货币价值。
在此之后,将该值分解为多种钞票与硬币的和,每种面值的钞票和硬币使用数量不限,要求使用的钞票和硬币的总数量尽可能少。
钞票的面值是 100,50,20,10,5,2
硬币的面值是 1,0.50,0.25,0.10,0.05和 0.01
经过实验证明:在本题中,优先使用面额大的钞票和硬币可以保证所用的钞票和硬币总数量最少。
输入格式
输入一个浮点数 N
输出格式
参照输出样例,输出每种面值的钞票和硬币的需求数量。
数据范围
0≤N≤1000000.00
输入样例
576.73
输出样例
NOTAS:
5 nota(s) de R$ 100.00
1 nota(s) de R$ 50.00
1 nota(s) de R$ 20.00
0 nota(s) de R$ 10.00
1 nota(s) de R$ 5.00
0 nota(s) de R$ 2.00
MOEDAS:
1 moeda(s) de R$ 1.00
1 moeda(s) de R$ 0.50
0 moeda(s) de R$ 0.25
2 moeda(s) de R$ 0.10
0 moeda(s) de R$ 0.05
3 moeda(s) de R$ 0.01
C代码
#include<cstdio>
using namespace std;
int main(){
double N;
double a[6] = {100,50,20,10,5,2};
double b[6] = {1.00,0.50,0.25,0.10,0.05,0.01};
scanf("%lf", &N);
//钞票
printf("NOTAS:\n");
for(int i = 0; i < 6; i ++){
int num = 0;
num = N / a[i];
printf("%d nota(s) de R$ %.2lf\n", num, a[i]);
N = N - (num * a[i]);
}
//硬币
printf("MOEDAS:\n");
for(int i = 0; i < 6; i ++){
int num = 0;
num = (int) (N / b[i] + 0.001);
printf("%d moeda(s) de R$ %.2lf\n", num, b[i]);
//给结果加上一个很小的值,再通过强制转换舍弃,可以避免一些无限二进制小数的精度问题
N = N - (num * b[i]);
}
return 0;
}
由于浮点数在计算机中是以二进制形式表示的,而某些十进制小数无法精确表示为有限位的二进制小数。例如,在第二个for循环中,0.1 在二进制中是一个无限循环小数 0.0001100110011…,因此在计算机中以浮点数存储时会存在精度问题。
当进行浮点数计算时,由于精度限制,一些操作可能导致结果略微偏离预期值。这就是为什么在程序中当计算机尝试将剩余金额 N 除以 0.01时,由于浮点数精度问题,可能会出现类似 0.9999999999999999 的结果,而非精确的 1,导致向下取整后与预期结果不符。这种微小的误差可能会影响最终输出的结果。
为了避免这种问题,可以通过添加一个很小的值(比如 10e-3,即 0.01),可以避免这种情况,因为这会导致除法结果向上取整。
例如,在计算 ( $\frac{n}{b[i]}$) 时,如果 ( n ) 和 ( b[i] ) 都是整数,并且 ( $\frac{n}{b[i]}$ ) 是一个小数,那么在进行整数除法后会丢失小数部分。但是,如果我们将分子或分母加上一个很小的值,比如 0.01,那么计算结果就会更接近实际的小数值。
- eg: 如果我们有一个表达式 ( $\frac{5}{2}$ ) 在整数除法中,结果会是 2 而不是 2.5,但是如果我们将分子或分母加上一个很小的值(比如0.01),即 ( $\frac{5+0.01}{2}$ ),那么结果会更接近 2.5 而不是向下取整的 2。
这种技巧在需要保留小数精度的情况下非常有用,特别是在涉及到浮点数计算的时候。