void main()
{
float f = 0.98;
if(f <= 0.98)
printf("hi");
else
printf("hello");
getch();
}
我在这里遇到了一个问题。使用不同的浮点数值f,我得到了不同的结果。为什么会出现这种情况?
void main()
{
float f = 0.98;
if(f <= 0.98)
printf("hi");
else
printf("hello");
getch();
}
f
使用了float
精度,但默认情况下0.98是double
精度,因此语句f <= 0.98
会使用double
精度进行比较。
因此,在比较中f
被转换为double
,但结果可能略大于0.98。
使用
if(f <= 0.98f)
或者使用 double
代替 f
。
float
是 IEEE 单精度浮点数格式,double
是 IEEE 双精度浮点数格式。0.98 = 0.1111101011100001010001111010111000010100011110101110000101000...
float
只能存储24位有效数字,即
0.111110101110000101000111_101...
^ round off here
= 0.111110101110000101001000
= 16441672 / 2^24
= 0.98000001907...
一个 double
可以存储53位有效数字,所以
0.11111010111000010100011110101110000101000111101011100_00101000...
^ round off here
= 0.11111010111000010100011110101110000101000111101011100
= 8827055269646172 / 2^53
= 0.97999999999999998224...
因此,在 float
中0.98会变得稍微更大,在 double
中会变得更小。
一个例子(来自我VB6时代遇到的问题)
要将数字1.1转换为单精度浮点数,我们需要将其转换为二进制。需要创建32位。
第1位是符号位(它是否为负[1]或正[0]) 位2-9用于指数值 位10-32用于尾数(也称为有效数字,基本上是科学计数法的系数)
因此,对于1.1,单精度浮点值存储如下(这是截断值,编译器可能会在幕后四舍五入最不重要的位,但我只是截断它,这样略微不太准确,但不会改变此示例的结果):
s --exp--- -------mantissa--------
0 01111111 00011001100110011001100
(1 + 099999904632568359375) * 2^(127-127)
(1 + 0.099999904632568359375) * 2^0
1.099999904632568359375 * 1 = 1.099999904632568359375
正如您所看到的,1.1实际上并没有以单精度浮点值1.1的形式存储。
void main(void)
记录为C标准5.1.2.2.1中指定的“其他实现定义方式”。我仍然认为在Microsoft C下,void main(void)
是可以接受的,但void main()
不行(这里没有足够的空间进行语言律师式的争论)。除非你正在使用独立实现,否则绝对没有理由定义具有void
返回类型的main
。 - Keith Thompsonint main(void)
更可取,但我很想听听为什么int main()
作为函数定义不行的更详细解释,有兴趣者请邮件联系(邮箱在个人资料中)。我使用的 GCC 编译器选项意味着我使用int main(void)
或者int main(int argc, char **argv)
而不是int main()
,但这并不是一个语言律师的论点。 - Jonathan Lefflerint main()
不等同于int main(void)
。后者会使main(42)
成为约束违规;前者则不会。另一方面,在ANSI C之前,int main()
肯定是正确的,并且意图是为了避免破坏旧代码,因此我认为应该允许使用int main()
(但已过时),但在我看来,标准文本当前的措辞并没有这样说明。 - Keith Thompson