浮点比较问题
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)
或者用f
来代替f
。
详细…假设float
是IEEE单精度 , double
是IEEE双精度 。
这些types的浮点数以base-2表示forms存储。 在基数2中,这个数字需要无限精度来表示,因为它是一个重复的小数:
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...
所以0.98将float
稍大, double
小。
这是因为浮点值不是数字的精确表示。 所有的十位数字都需要在计算机上表示为基数2的数字。 正是在这种转换中,精确度被丢失了。
在http://en.wikipedia.org/wiki/Floating_point上阅读更多信息;
一个例子(从我的VB6时代遇到这个问题)
要将数字1.1转换为单精度浮点数,我们需要将其转换为二进制。 有32位需要被创build。
位1是符号位(是负数[1]还是位置[0])位2-9是指数值位10-32是尾数(又名有效数,基本上是科学计数系数)
因此,对于1.1单浮点值存储如下(这是截断的值,编译器可能四舍五入后面的最不重要的位,但我所做的是截断它,这是不太准确,但不会改变结果这个例子):
s --exp--- -------mantissa-------- 0 01111111 00011001100110011001100
如果你注意到尾数有重复模式0011.二进制的1/10就像十进制的1/3。 它永远持续下去。 因此,要从32位单精度浮点值中检索值,我们必须首先将指数和尾数转换为十进制数,以便我们可以使用它们。
sign = 0 =一个正数
指数:01111111 = 127
尾数:00011001100110011001100 = 838860
尾数,我们需要将其转换为十进制值。 原因是在二进制数之前有一个隐含的整数(即1.00011001100110011001100)。 隐含的数字是因为尾数代表在科学计数法中使用的标准化值:1.0001100110011 …. * 2 ^(x-127)。
为了得到838860的十进制值,我们简单地除以2 ^ -23,因为尾数有23位。 这给了我们0.099999904632568359375。 添加隐含1到尾数给出1.099999904632568359375。 指数是127,但公式要求2 ^(x-127)。
所以这是math:
(1 + 099999904632568359375)* 2 ^(127-127)
1.099999904632568359375 * 1 = 1.099999904632568359375
正如你所看到的,1.1实际上并不是以1.1的forms存储在单个浮点值中。