(楼层)如何在C中实际工作?据techonthenet说。 com,
在C编程语言中,floor函数返回小于或等于x的最大整数(即:舍入最接近的整数)。
在将值4.2输入到get_float()之后,我使用floor(4.2 * 100)将它们转换为美分并删除小数位并使其成为整数。
但是,我很困惑为什么专门输入值4.2会为楼层(4.2 * 100)和楼层(4.2 * 1000/10)返回不同的值?这与不精确有关吗?
见图:When variable entered as 4.2, floor produces different values
顺便说一下,我刚刚开始使用edx上的CS50,并且尝试了第1周课程的最后一次练习...也会喜欢对代码其他部分的任何评论。关于这个问题的更多信息:http://docs.cs50.net/problems/greedy/greedy.html
这与不精确有关吗?
它与不精确有关。
您不能用有限的位数表示无限数量的浮点值,因此实际存储在浮点类型中的是大多数值的近似值。 4.2
无法用32位float
类型完全表示;实际存储的是更接近4.199999809
的东西。
你需要48位有效数字来表示它,这意味着你需要使用64位double
。
=叹气=我无法添加。 double
让你更接近4.2,但不完全正确。
这只是谈论存储,而不是算术运算中的舍入和错误传播。
一般来说,最好使用double
而不是float
进行浮点工作(更大的范围和精度)。此外,最好将货币金额存储在整数类型中,缩放到最小单位(例如,而不是存储4.2
美元,存储420
美分或4200
密尔)。您仍然需要使用浮点类型来计算兴趣和类似的东西,但是您需要在执行适当的舍入和缩放后将这些结果存储回整数类型。
float/double
不能完全代表所有可能的数字。典型的float
可以代表大约232个不同的数字。 4.2不是其中之一。而是使用最近的值。打印using FLT_DECIMAL_DIG
以查看足够的数字精度,知道它不完全是4.2
#include <float.h>
float a = 4.2f;
printf("%.*e\n", FLT_DECIMAL_DIG-1, a);
// 4.19999981e+08
a *= 100;
printf("%.*e\n", FLT_DECIMAL_DIG-1, a);
// 4.19999969e+02
a = floor(a);
printf("%.*e\n", FLT_DECIMAL_DIG-1, a);
// 4.19000000e+02
随着a*100
和a*1000
产品四舍五入到最接近的可回答的答案和回忆,a
不完全是4.2。
a = 4.2;
printf("%.*e\n", FLT_DECIMAL_DIG-1, a * 100); // 4.19999969e+02
printf("%f\n", floor(a * 100)); // 419.000000
printf("%.*e\n", FLT_DECIMAL_DIG-1, a * 1000); // 4.20000000e+03
printf("%.*e\n", FLT_DECIMAL_DIG-1, a * 1000/10); // 4.20000000e+02
printf("%f\n", floor(a * 1000 / 10)); // 420.000000
当数字需要四舍五入到最接近的0.01时,使用floor()
将4.2分成整数和分数是一个不好的选择。相反,使用匹配类型函数进行缩放,舍入然后分离。
float a100 = a*100;
printf("%.*e\n", FLT_DECIMAL_DIG-1, a100); // 4.19999969e+02
a100 = roundf(a100);
printf("%.*e\n", FLT_DECIMAL_DIG-1, a100); // 4.20000000e+02
float a100th = fmodf(a100, 100);
printf("%.*e\n", FLT_DECIMAL_DIG-1, a100th); // 2.00000000e+01
a = (a100 - a100th)/100;
printf("%.*e\n", FLT_DECIMAL_DIG-1, a); // 4.00000000e+00
金钱在C中有许多特殊问题,各种方法都有weaknesses。使用float
是一个非常弱的选择。
在尝试降低值之前,打印美元的值以查看实际存储的内容。