C语言如何正确将小数四舍五入保留两位小数 解决货币找零精度问题
货币找零程序问题修复方案
问题根源
问题是二进制浮点数的固有精度限制导致的:float 类型无法精确表示 0.01、0.2 这类十进制小数,输入的99.99实际存储时会是略小于99.99的数值(例如99.98999786),运算过程中误差持续累计,最后就会出现差0.01无法正确识别的问题,单独调用取整函数也无法解决底层的精度误差。
推荐修复方案:统一转换为整数(单位:分)运算
完全规避浮点数误差的最优方案是把所有金额换算为以「分」为单位的整数进行计算,同时保留你原有的指针用法,修改后代码如下:
#include <stdio.h> #include <math.h> #define COINS_TYPES 14 // 新增:元转分的换算系数 #define YUAN_TO_FEN 100 void read_num(int* cash_fen); void analyze_and_result(int* arr, int* arr_val_fen, int* cash_fen); int main(){ int cash_fen; int coins[COINS_TYPES] = { 0 }; // 面值全部转为分单位的整数 int coins_val_fen[COINS_TYPES] = { 20000,10000,5000,2000,1000,500,200,100,50,20,10,5,2,1 }; for (;;) { read_num(&cash_fen); analyze_and_result(coins, coins_val_fen, &cash_fen); break; } return 0; } void read_num(int* cash_fen) { float cash; printf("Type amount of cash to exchange for coins\n"); scanf("%f", &cash); // 转成分单位整数,加1e-6避免浮点数取整误差 *cash_fen = (int)(cash * YUAN_TO_FEN + 1e-6); } void analyze_and_result(int* arr, int* arr_val_fen, int* cash_fen) { for (int i = 0;i < COINS_TYPES;i++) { int flag = *cash_fen / arr_val_fen[i]; if (flag) { arr[i] = flag; *cash_fen -= arr_val_fen[i] * flag; // 输出时转换回元单位,格式和原来一致 printf("Coins quantity %0.2f : %d\n", arr_val_fen[i] * 1.0 / YUAN_TO_FEN, arr[i]); } } }
改动说明
- 所有金额计算全部改用
int类型以分为单位运算,从根源上消除浮点数精度误差 - 保留了原有的指针传参逻辑,符合你学习指针的需求
- 输入时先读取浮点金额再转成分整数,兼容用户的输入习惯
- 输出时自动转回元单位,和原有输出格式完全一致
临时应急方案(不改动数据类型)
如果你暂时不想修改整体数据结构,可以在计算面值数量时补充极小的误差修正值抵消精度问题,仅需要修改analyze_and_result里的flag计算逻辑:
// 加1e-6抵消浮点数累计误差 int flag = (*cash + 1e-6) / arr_val[i];
该方案仅能临时解决问题,长期使用还是推荐整数运算的方案,可靠性更高。
内容的提问来源于stack exchange,提问作者DrugaSzychta
相关产品推荐
相关产品推荐

