While 循环忽略比较两个浮点变量的布尔表达式

While loop ignores a boolean expression which compares two floating point variables

编辑:
我解决了这个问题,方法是先将浮点值乘以 100,然后使用 roundf() 函数对其进行舍入,然后将其转换为整数以存储在整数变量中。从那以后,我用整数值做了剩下的操作,一切正常。尽管@JacobBoertjes 提供的解决方案确实有效,但我的作业要求我使用 cs50.h 库中的 get_float(),所以我没有实现它。这是最终代码:

// Get user input as a positive float value
float f_change;
do {
    printf("Change owed: ");
    f_change = get_float();
} while(f_change < 0);

// Round & cast
int int_change = (int) roundf(f_change * 100);

我的程序接受一定数量的钱,比如 4.20 美元,并计算出可以表示该值的最少硬币数量。例如,以 $4.20 作为输入的程序的期望输出为:16 个季度($4.00)、2 个硬币($0.20)。

我的程序成功计算了季度数,但未能在做硬币的同时这样做。导致这个失败的原因是代码中的第二个for循环0.10 >= 0.10 计算结果不为真,因此循环的最后一次迭代永远不会发生。我究竟做错了什么?

这是代码。我提供了测试打印语句,并将其输出写为注释。

#include <stdio.h>
#include <cs50.h>

int main(void) {

  // Fake user input
  float owed_coin = 4.2f;

  // Initialize coin variables
  int coin_count = 0;

  float quarters = 0.25f,
        dimes = 0.10f;

  // Calculate quarters
  while(owed_coin >= quarters) {
    owed_coin -= quarters;
    coin_count += 1;
  }
  printf("owed_coin: %.2f\ncoin_count: %d\n\n", owed_coin, coin_count);
  // Prints  owed_coin: 0.20
  //         coin_count: 16

  // Calculate dimes
  while(owed_coin >= dimes) {
    owed_coin -= dimes;
    coin_count += 1;
  }
  printf("owed_coin: %.2f\ncoin_count: %d\n\n", owed_coin, coin_count);
  // Prints  owed_coin: 0.10
  //         coin_count: 17

}

浮点数比较通常不是一个好主意,因为浮点数通常变得不精确,因此不会完全相等。正如@bruceg 所提到的,一个好的解决方案是以美分表示您的货币价值,这样您就可以避免使用浮点数。

您可以将 float owed_coin = 4.2f; 替换为 int owed_coin = 420;

关于将用户输入收集到此号码,这是我的建议 scanf

int n1, n2;

printf("Please enter amount:");
scanf("%d.%2d", &n1, &n2);

owed_coin = n1*100 + n2;

另一个解决方案允许您将变量保持为浮点数,并且只比较两者之间的非常小的差异。可以在这里找到:What's wrong with using == to compare floats in Java?

它使用 Java 数学库,但类似的解决方案在 C:

中可能看起来像这样
while((owed_coin - dimes) >= -0.001) {
    owed_coin -= dimes;
    coin_count += 1;
}

如果您想详细了解为什么浮点数会出现一些小错误,请查看:https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems