beecrowd 1021:输入576.73时金额转分计算异常问题
Beecrowd 1021题:输入576.73时分币计算错误问题
这段C语言代码在处理多数金额时能正常输出纸币和硬币的数量,但输入576.73时,分币(R$ 0,01)的计算结果会出错。
原代码
#include <stdio.h> #include <math.h> int calculo(float num); int main() { float numero; scanf("%f",&numero); calculo(numero); return 0; } int calculo(float num) { //TRANSFORMA PARA INTEIRO int n; //NOTAS int n100, n50, n20, n10, n5, n2; //MOEDAS int m1, m05, m025, m010, m005, m001; //NOTAS n = floor(num); n100 = n/100; n50 = (n%100)/50; n20 = ((n%100)%50)/20; n10 = (((n%100)%50)%20)/10; n5 = ((((n%100)%50)%20)%10)/5; n2 = (((((n%100)%50)%20)%10)%5)/2; //MOEDAS m1 = (((((n%100)%50)%20)%10)%5)%2; n = num*100; n = (int) n*1; n = n%100; m05 = n/50; n = n%50; m025 = n/25; n = n%25; m010 = n/10; n = n%10; m005 = n/5; m001 = n%5; printf("NOTAS:\n"); printf("%d nota(s) de R$ 100,00\n",n100); printf("%d nota(s) de R$ 50,00\n",n50); printf("%d nota(s) de R$ 20,00\n",n20); printf("%d nota(s) de R$ 10,00\n",n10); printf("%d nota(s) de R$ 5,00\n",n5); printf("%d nota(s) de R$ 2,00\n",n2); printf("MOEDAS:\n"); printf("%d moeda(s) de R$ 1,00\n",m1); printf("%d moeda(s) de R$ 0,50\n",m05); printf("%d moeda(s) de R$ 0,25\n",m025); printf("%d moeda(s) de R$ 0,10\n",m010); printf("%d moeda(s) de R$ 0,05\n",m005); printf("%d moeda(s) de R$ 0,01\n",m001); return 0; }
问题原因
核心是浮点数精度丢失:
float属于单精度浮点数,无法精确表示所有十进制小数(比如576.73)。当执行num*100时,实际计算结果是57672.999999...而非精确的57673,强制转换为int类型时会直接截断小数部分,得到57672,后续分币计算就会少1个0.01的硬币。
修复方案
方案1:用round()函数四舍五入
修改处理小数部分的关键代码,先对num*100的结果四舍五入,再转换为整数:
// 替换原来的n = num*100; n = (int) n*1; n = round(num * 100); // 四舍五入后得到精确的分数值
方案2:改用double类型提升精度
将float替换为double,再配合四舍五入,能进一步减少精度问题:
// main函数中把float numero改为double numero double numero; scanf("%lf", &numero); // calculo函数的参数也改为double int calculo(double num) { // ... n = round(num * 100); // ... }
方案3:直接读取整数形式的金额
如果输入格式允许,可以直接读取以分为单位的整数,完全避免浮点数运算:
// 比如输入57673代表576.73雷亚尔 int numero; scanf("%d", &numero);
修复后的完整代码示例
#include <stdio.h> #include <math.h> int calculo(double num); int main() { double numero; scanf("%lf",&numero); calculo(numero); return 0; } int calculo(double num) { int n; int n100, n50, n20, n10, n5, n2; int m1, m05, m025, m010, m005, m001; // 处理纸币部分 n = floor(num); n100 = n/100; n50 = (n%100)/50; n20 = ((n%100)%50)/20; n10 = (((n%100)%50)%20)/10; n5 = ((((n%100)%50)%20)%10)/5; n2 = (((((n%100)%50)%20)%10)%5)/2; m1 = (((((n%100)%50)%20)%10)%5)%2; // 处理硬币部分,修复精度问题 n = round(num * 100); n = n%100; m05 = n/50; n = n%50; m025 = n/25; n = n%25; m010 = n/10; n = n%10; m005 = n/5; m001 = n%5; printf("NOTAS:\n"); printf("%d nota(s) de R$ 100,00\n",n100); printf("%d nota(s) de R$ 50,00\n",n50); printf("%d nota(s) de R$ 20,00\n",n20); printf("%d nota(s) de R$ 10,00\n",n10); printf("%d nota(s) de R$ 5,00\n",n5); printf("%d nota(s) de R$ 2,00\n",n2); printf("MOEDAS:\n"); printf("%d moeda(s) de R$ 1,00\n",m1); printf("%d moeda(s) de R$ 0,50\n",m05); printf("%d moeda(s) de R$ 0,25\n",m025); printf("%d moeda(s) de R$ 0,10\n",m010); printf("%d moeda(s) de R$ 0,05\n",m005); printf("%d moeda(s) de R$ 0,01\n",m001); return 0; }
内容的提问来源于stack exchange,提问作者Henrique Bispo
相关产品推荐
相关产品推荐

