为什么ceil()会在没有小数部分的情况下进行均匀浮动? 当我尝试这样做时:
double x = 2.22;
x *= 100; //which becomes 222.00...
printf("%lf", ceil(x)); //prints 223.00... (?)
但是当我将2.22的值更改为2.21
时x *= 100; //which becomes 221.00...
printf("%lf", ceil(x)); //prints 221.00... as expected
我尝试用另一种方式使用modf()并遇到另一个奇怪的事情:
double x = 2.22 * 100;
double num, fraction;
fraction = modf(x, &num);
if(fraction > 0)
num += 1; //goes inside here even when fraction is 0.00...
那么会发生什么是0.000 ...大于0?
谁能解释为什么这两种情况都会发生?此外,我正在使用RedHat中的cc版本4.1.2进行编译。
答案 0 :(得分:12)
基本答案是你得到的浮点数:
double x = 2.22;
实际上比值2.22
稍微大一点,以及
double x = 2.21;
比2.21
小一点。
答案 1 :(得分:12)
这是正常的,因为数字是使用二进制存储的。虽然您的数字可以使用十进制数字写入有限数字,但这不适用于二进制数。
您应该阅读Goldberg的报告What Every Computer Scientist Should Know About Floating-Point Arithmetic。
答案 2 :(得分:7)
并非所有浮点值都可以由float
和double
C类型正确表示 - 您认为222
很可能实际上类似于222.00000000000000001
。< / p>
有一种标准的,但鲜为人知的解决方法 - 使用nextafter()
C99功能:
printf("%lf", ceil(nextafter(x, 0)));
有关详细信息,请参阅man nextafter
。
答案 3 :(得分:2)
那是因为2.22不完全是2.22因此2.22 * 100不是222而是222.000000000x
double x = 2.22;
printf("%.20lf\n", x); //prints 2.22000000000000019540
x *= 100;
printf("%.20lf\n", x); //prints 222.00000000000002842171
如果你需要整数精度(例如计算金钱相关的东西),请使用积分算术(即计算美分而不是美元)。
答案 4 :(得分:1)
如果你要写:
const int x = 1.2;
在C程序中,会发生什么?文字1.2
不能表示为整数值,因此编译器会根据通常的规则转换为整数,x
将被赋值为1
。
同样的事情发生在这里。
您写道:
double x = 2.22;
2.22
不能表示为双精度数,因此编译器会根据C标准中的规则对其进行转换。您将得到最接近的可表示的双精度数,正好是:
2.220000000000000195399252334027551114559173583984375
在double
中将此值乘以100时,结果为:
222.000000000000028421709430404007434844970703125
当您使用该值作为参数调用ceil( )
时,数学库会正确返回223.0
。
答案 5 :(得分:0)
您可能需要考虑使用decimal floating point types来获得您期望的十进制算术结果。典型台式PC处理器上的硬件仅支持二进制浮点,因此不能期望产生与十进制计算相同的结果。当然,如果硬件不支持,则十进制浮点速度较慢。
请注意,十进制浮点不一定更精确(例如1/3不能精确表示,就像二进制FP中的值无法表示一样),它只会产生期望值结果,就像你用十进制长手计算一样。