【问题标题】:Printing values of float and int for a simple calculation (values not adding up)打印 float 和 int 的值以进行简单计算(值不相加)
【发布时间】:2023-04-02 14:45:02
【问题描述】:

设计用于将美元值输入转换为其可能的组成部分的程序的浮点/整数计算存在问题。例如,如果您输入 1234.56 美元,程序将输出“1 张 1000 美元钞票、2 张 100 美元钞票、1 张 20 美元钞票、1 张 10 美元钞票、4 张 4 美元钞票、2 个夸特、1 张镍和 1 美分”。

最大的问题是计算便士。如果用户输入 $ .03,输出会有所不同(有时,我得到 3 美分;其他时候,我得到 2 美分)。我想我现在已经解决了这个问题,但我想了解我为什么解决它,更重要的是我想解决根本问题:在计算流的某个地方,编译器似乎“削减”了值(例如.01 变为 .009999)。是因为我正在对同一个变量(即“金额”)执行递归计算吗?有没有更清洁的方法来做我在这里想做的事情? (我仅限于 switch / if 选择语句,没有使用函数,也没有使用数组。)

链接到完整代码here

#include <stdio.h>

int main(){

float amount, bill_quarter_f, bill_dime_f, bill_nickel_f, bill_penny_f;
int bill_quarter, bill_dime, bill_nickel, bill_penny;

printf("Ex 5.15: Translating Decimal Dollar into Coins\n");
printf("==============================================\n\n");

printf("Enter your amount (e.g .98): $ ");
scanf("%f", &amount);

/************************************/
/* Calculation for greater than MAX */
/************************************/

if (amount >= 1)
    printf("\nYou have too much money!\n\n");

/************************************/
/*       Calculation for Coins      */
/************************************/

else if(amount < 1 && amount > 0){
    bill_quarter = amount / .25;
    bill_quarter_f = amount / .25;
    amount = ((bill_quarter_f - bill_quarter) * .25);


    (bill_quarter >= 1 && bill_quarter < 4) ? (printf("You have %d quarters\n", bill_quarter)) : (printf(""));

    bill_dime = amount / .10;
    bill_dime_f = amount / .10;
    amount = (bill_dime_f - bill_dime) * .10;


    (bill_dime >= 1 && bill_dime <= 2) ? (printf("You have %d dimes\n", bill_dime)) : (printf(""));

    bill_nickel = amount / .05;
    bill_nickel_f = amount / .05;
    amount = (bill_nickel_f - bill_nickel) * .05;


    (bill_nickel >= 1 && bill_nickel < 2) ? (printf("You have %d nickel\n", bill_nickel)) : (printf(""));

    bill_penny = amount / .01;
    bill_penny_f = amount / .01;
    amount = (bill_penny_f - bill_penny) * .01;

    (bill_penny_f > 0 && bill_penny_f < 5) ? (printf("You have %.0f pennies\n", bill_penny_f)) : (printf(""));
}

else if (amount == 0)
    printf("You have no money!\n");
else
    printf("You are in debt!\n");

return 0;
}

【问题讨论】:

  • 对货币类型使用定点算法;浮点完全不合适(尤其是二进制浮点)。
  • @TobySpeight 货币类型的定点算法也有它的弱点。 “浮点完全不合适”--> 十进制 FP 很棒——除了缺乏支持。无论采取何种路线,它都是一种权衡。
  • @chux,我从未尝试过十进制浮点数;我宁愿将这些指数数字用于实际值,而不是用于缩放(因此在意外时间改变(绝对)精度)。但是,如果您有经验,我很想听听它对您的作用,也许在某个地方的答案中?
  • @OP “是因为我在表演……[这个]还是[那个]?” --> 关键是当使用 FP 来赚钱时,代码需要定义如何处理仅接近最小单位 0.01 的倍数的结果。
  • @chux 感谢您的回答。我的帖子有什么不完整的地方?我是一个初学者,并不是我想依靠它,但我对为什么我的帖子不完整感到困惑。最后,作者(KN King)目前介绍的唯一变量类型是 float 和 int;所以,我想知道这个练习是否是为了迫使读者避免使用浮点数。

标签: c floating-point


【解决方案1】:

在财务代码中使用二进制浮点存在各种缺陷。 OP 的代码展示了其中的一些。在不涉及其他其他表示金钱的方式(每种方式都有其优点和缺点)的情况下,此答案提供了改进 double 使用金钱的方法,因为它适用于 OP 的代码。

  1. 货币的不准确表示

回想一下 binary64 double 通常完全代表大约 264 个不同的数字。 0.10 不是其中之一。所以下面的商往往会得到一个非整数。

float amount;
...
amount / .10;

将商分配给int 会导致值被截断。如果 quotient 是 1.9999...,bill_dime 将采用 1 的值。

int bill_dime;
...
bill_dime = amount / .10;
  1. 无法控制不是 0.01 的精确倍数的输入。

如何处理"0.125" 之类的用户输入 --> amount = 0.125

0.125 可以精确地表示为double,因此输入不存在舍入问题。然而,代码并没有说明如何对这样的值进行舍入或如何处理 0.01 的小数部分。

  1. 无法控制输入四舍五入的值。

如何处理像"0.10" 这样的用户输入 --> 不能精确表示该值?所以附近的amount = 0.10f 结果。

value 采用float0.01f接近 0.01,可能与double 0.01 不同。这种差异可能会导致来自amount / .10; 的意外结果。混合doublefloat 导致了这个问题。


对于使用 FP 的财务代码,不要使用float - 问题太多了。

对于 OP 的学习者使用 FP 和金融代码,建议将 FP 输入转换为整数以进行变化计算。由于下面的long的转换肯定不会溢出,所以可以抛开对OF的顾虑。

printf("Enter your amount (e.g .98): $ ");
double amount;
if (scanf("%lf", &amount) != 1) Handle_NonNumericInput();

if (amount >= 1.0 || amount < 0.0)
  printf("\nYou have too much/too little money!\n\n");

现在转到整数

 else {
   // round ... to the nearest integer value, rounding halfway cases away from zero,
   long cents = lround(amount * 100.0);
   // 0 <= cents <= 100
   // Need to decide how to handle cents == 0 or cents == 100 here.

   bill_quarter = cents / 25;
   cents %= 25;

   if (bill_quarter) {
     printf("You have %d quarters\n", bill_quarter);
   }

  bill_dime = cents / 10;
  cents %= cents % 10;

   if (bill_dime) {
     printf("You have %d dimes\n", bill_dime);
   }

次要

// "You have %d nickel"
"You have %d nickels"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-18
    • 2012-03-28
    • 1970-01-01
    • 1970-01-01
    • 2020-12-06
    • 1970-01-01
    • 1970-01-01
    • 2020-12-28
    相关资源
    最近更新 更多