C语言硬币金额换算程序计算错误排查:精度问题求助
硬币金额换算程序的精度问题排查与修复
问题描述
任务是编写程序将金额换算为不同面值的硬币,仅允许使用<stdio.h>、取模和除法操作。
预期输出
Coin Qty Balance -------- --- --------- 365.5700 Toonies 182 1.5700 Loonies 1 0.5700 Quarters 2 0.0700 Dimes 0 0.0700 Nickels 1 0.0200 Pennies 2 0.0000
实际输出
Coin Qty Balance -------- --- --------- 365.5700 Toonies 182 1.5700 Loonies 1 0.5700 Quarters 2 0.0600 Dimes 0 0.0600 Nickels 1 0.0100 Pennies 1 0.0000
原代码
#include <stdio.h> int main() { double total = 365.5700; int toonies, loonies, quarters, dimes, nickels, pennies; double balToonies, balLoonies, balQuarters, balDimes, balNickels, balPennines; // Toonies toonies = (int)total / 2; balToonies = (int)(total * 100) % 200 / 100.0; // Loonies loonies = (int)balToonies / 1; balLoonies = (int)(balToonies * 100) % 100 / 100.0; // Quarters quarters = (int)(balLoonies * 100) / 25; balQuarters = (int)(balLoonies * 100) % 25 / 100.0; // Dimes dimes = (int)(balQuarters * 100) / 10; balDimes = (int)(balQuarters * 100) % 10 / 100.0; // Nickels nickels = (int)(balDimes * 100) / 5; balNickels = (int)(balDimes * 100) % 5 / 100.0; // Pennies pennies = (int)(balNickels * 100) / 1; balPennines = (int)(balNickels * 100) % 1 / 100.0; printf("Coin Qty Balance\n"); printf("-------- --- ---------\n"); printf("%22.4lf\n", total); printf("Toonies %3d %9.4lf\n", toonies, balToonies); printf("Loonies %3d %9.4lf\n", loonies, balLoonies); printf("Quarters %3d %9.4lf\n", quarters, balQuarters); printf("Dimes %3d %9.4lf\n", dimes, balDimes); printf("Nickels %3d %9.4lf\n", nickels, balNickels); printf("Pennies %3d %9.4lf\n\n", pennies, balPennines); return 0; }
问题根源
核心问题是浮点数精度误差。double类型无法精确表示所有十进制小数,比如365.57在二进制浮点数中是一个无限循环的近似值,实际存储的值略小于365.57。当执行(int)(balLoonies * 100)时,balLoonies是0.57的近似值,乘以100后得到的是接近57但略小于57的数,强制转换为int后就变成了56,后续所有计算都因此出错。
修复方案
全程使用整数处理,将金额转换为以分为单位的整数,彻底避免浮点数精度问题。所有硬币面值也统一用分来表示:
- Toonies:200分
- Loonies:100分
- Quarters:25分
- Dimes:10分
- Nickels:5分
- Pennies:1分
修正后的代码
#include <stdio.h> int main() { // 将金额转换为以分为单位的整数,避免浮点数误差 int total_cents = 36557; int toonies, loonies, quarters, dimes, nickels, pennies; int balance; // 初始余额为总分数 balance = total_cents; // Toonies(200分) toonies = balance / 200; balance = balance % 200; // Loonies(100分) loonies = balance / 100; balance = balance % 100; // Quarters(25分) quarters = balance / 25; balance = balance % 25; // Dimes(10分) dimes = balance / 10; balance = balance % 10; // Nickels(5分) nickels = balance / 5; balance = balance % 5; // Pennies(1分) pennies = balance; balance = 0; // 格式化输出,将分数转换回元显示 printf("Coin Qty Balance\n"); printf("-------- --- ---------\n"); printf("%22.4lf\n", total_cents / 100.0); printf("Toonies %3d %9.4lf\n", toonies, (total_cents % 200) / 100.0); printf("Loonies %3d %9.4lf\n", loonies, (total_cents % 200 % 100) / 100.0); printf("Quarters %3d %9.4lf\n", quarters, (total_cents % 200 % 100 % 25) / 100.0); printf("Dimes %3d %9.4lf\n", dimes, (total_cents % 200 % 100 % 25 % 10) / 100.0); printf("Nickels %3d %9.4lf\n", nickels, (total_cents % 200 % 100 % 25 % 10 % 5) / 100.0); printf("Pennies %3d %9.4lf\n\n", pennies, 0.0); return 0; }
代码说明
- 用
total_cents存储总金额的分数(365.57元 = 36557分),完全避免浮点数操作。 - 每一步计算硬币数量时,用整数除法得到数量,取模得到剩余余额(分数)。
- 输出时将分数转换回元(除以100.0),保证显示格式符合要求。
这样计算出来的结果完全符合预期输出,不会出现精度误差。
内容的提问来源于stack exchange,提问作者SSY
相关产品推荐
相关产品推荐

