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
编辑:
我解决了这个问题,方法是先将浮点值乘以 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