另一个近乎精确的问题与这个问题有关,因此迟到了几年的答案。我认为以上答案并不完整。
int fun1 ( void )
{
float x=0.7;
if(x==0.7) return(1);
else return(0);
}
int fun2 ( void )
{
float x=1.1;
if(x==1.1) return(1);
else return(0);
}
int fun3 ( void )
{
float x=1.0;
if(x==1.0) return(1);
else return(0);
}
int fun4 ( void )
{
float x=0.0;
if(x==0.0) return(1);
else return(0);
}
int fun5 ( void )
{
float x=0.7;
if(x==0.7f) return(1);
else return(0);
}
float fun10 ( void )
{
return(0.7);
}
double fun11 ( void )
{
return(0.7);
}
float fun12 ( void )
{
return(1.0);
}
double fun13 ( void )
{
return(1.0);
}
Disassembly of section .text:
00000000 <fun1>:
0: e3a00000 mov r0, #0
4: e12fff1e bx lr
00000008 <fun2>:
8: e3a00000 mov r0, #0
c: e12fff1e bx lr
00000010 <fun3>:
10: e3a00001 mov r0, #1
14: e12fff1e bx lr
00000018 <fun4>:
18: e3a00001 mov r0, #1
1c: e12fff1e bx lr
00000020 <fun5>:
20: e3a00001 mov r0, #1
24: e12fff1e bx lr
00000028 <fun10>:
28: e59f0000 ldr r0, [pc] ; 30 <fun10+0x8>
2c: e12fff1e bx lr
30: 3f333333 svccc 0x00333333
00000034 <fun11>:
34: e28f1004 add r1, pc, #4
38: e8910003 ldm r1, {r0, r1}
3c: e12fff1e bx lr
40: 66666666 strbtvs r6, [r6], -r6, ror #12
44: 3fe66666 svccc 0x00e66666
00000048 <fun12>:
48: e3a005fe mov r0, #1065353216 ; 0x3f800000
4c: e12fff1e bx lr
00000050 <fun13>:
50: e3a00000 mov r0, #0
54: e59f1000 ldr r1, [pc] ; 5c <fun13+0xc>
58: e12fff1e bx lr
5c: 3ff00000 svccc 0x00f00000 ; IMB
为什么 fun3 和 fun4 返回一个而不是其他?为什么 fun5 有效?
这是关于语言的。该语言说 0.7 是双精度,除非您使用这种语法 0.7f 然后它是单精度。所以
float x=0.7;
double 0.7 转换为 single 并存储在 x 中。
if(x==0.7) return(1);
语言说我们必须提升到更高的精度,以便将 x 中的单精度转换为双精度并与双精度 0.7 进行比较。
00000028 <fun10>:
28: e59f0000 ldr r0, [pc] ; 30 <fun10+0x8>
2c: e12fff1e bx lr
30: 3f333333 svccc 0x00333333
00000034 <fun11>:
34: e28f1004 add r1, pc, #4
38: e8910003 ldm r1, {r0, r1}
3c: e12fff1e bx lr
40: 66666666 strbtvs r6, [r6], -r6, ror #12
44: 3fe66666 svccc 0x00e66666
单 3f333333
双3fe6666666666666
正如 Alexandr 指出的那样,如果这个答案仍然是 IEEE 754,那么单个是
见eeeeeeffffffffffffffffffffffff
双是
见啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊
52 位小数,而不是单人的 23 位。
00111111001100110011... single
001111111110011001100110... double
0 01111110 01100110011... single
0 01111111110 01100110011... double
就像以 10 为底的 1/3 是 0.3333333...永远一样。我们这里有一个重复的模式 0110
01100110011001100110011 single, 23 bits
01100110011001100110011001100110.... double 52 bits.
这就是答案。
if(x==0.7) return(1);
x 包含 01100110011001100110011 作为它的分数,当它被转换回来时
分数加倍是
01100110011001100110011000000000....
不等于
01100110011001100110011001100110...
这里
if(x==0.7f) return(1);
升级不会发生相同的位模式相互比较。
为什么 1.0 有效?
00000048 <fun12>:
48: e3a005fe mov r0, #1065353216 ; 0x3f800000
4c: e12fff1e bx lr
00000050 <fun13>:
50: e3a00000 mov r0, #0
54: e59f1000 ldr r1, [pc] ; 5c <fun13+0xc>
58: e12fff1e bx lr
5c: 3ff00000 svccc 0x00f00000 ; IMB
0011111110000000...
0011111111110000000...
0 01111111 0000000...
0 01111111111 0000000...
在这两种情况下,分数都是零。因此,从双精度到单精度再到双精度不会损失任何精度。它将单精度转换为双精度,并且两个值的位比较有效。
halfdan 投票和检查的最高答案是正确答案,这是混合精度的情况,您永远不应该进行相等比较。
该答案中未显示原因。 0.7 失败 1.0 有效。为什么 0.7 失败没有显示。重复的问题 1.1 也失败了。
编辑
这里的等号可以从问题中去掉,这是一个已经被回答的不同的问题,但它是同一个问题,也有“what the ...”的初始震惊。
int fun1 ( void )
{
float x=0.7;
if(x<0.7) return(1);
else return(0);
}
int fun2 ( void )
{
float x=0.6;
if(x<0.6) return(1);
else return(0);
}
Disassembly of section .text:
00000000 <fun1>:
0: e3a00001 mov r0, #1
4: e12fff1e bx lr
00000008 <fun2>:
8: e3a00000 mov r0, #0
c: e12fff1e bx lr
为什么一个显示小于,另一个显示不小于?什么时候应该相等。
从上面我们知道了 0.7 的故事。
01100110011001100110011 single, 23 bits
01100110011001100110011001100110.... double 52 bits.
01100110011001100110011000000000....
小于。
01100110011001100110011001100110...
0.6 是不同的重复模式 0011 而不是 0110。
但是当从双精度转换为单精度时或通常表示时
作为单个 IEEE 754。
00110011001100110011001100110011.... double 52 bits.
00110011001100110011001 is NOT the fraction for single
00110011001100110011010 IS the fraction for single
IEEE 754 使用舍入模式,向上舍入、向下舍入或舍入为零。默认情况下,编译器倾向于四舍五入。如果你记得在小学四舍五入 12345678,如果我想从顶部四舍五入到第三位,那将是 12300000,但如果后面的数字是 5 或更大,则四舍五入到下一个数字 1235000,然后四舍五入。 5 是 10 的 1/2,二进制 1 中的底数(十进制)是底数的 1/2,所以如果我们要四舍五入的位置之后的数字是 1,则四舍五入,否则不要。所以对于 0.7 我们没有四舍五入,对于 0.6 我们确实四舍五入。
现在很容易看到
00110011001100110011010
由于 (x
00110011001100110011010000000000....
大于
00110011001100110011001100110011....
所以不用说使用 equals,问题仍然存在 0.7 是双精度 0.7f 是单精度,如果它们不同,则运算会提升到最高精度。