Другой почти точный вопрос был связан с этим, таким образом, запоздалый ответ. Я не думаю, что приведенные выше ответы полны.
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;
двойной 0,7 преобразуется в один и сохраняется в х.
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
Как отметил Александр, если этот ответ остается IEEE 754, то один -
seeeeeeeefffffffffffffffffffffff
И двойной
seeeeeeeeeeeffffffffffffffffffffffffffffffffffffffffffffffffffff
с 52 битами дроби, а не с 23, которые имеют сингл.
00111111001100110011... single
001111111110011001100110... double
0 01111110 01100110011... single
0 01111111110 01100110011... double
Точно так же, как 1/3 в базе 10 - это 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...
В обоих случаях дробь - все нули. Таким образом, преобразование из двойного в одинарный для двойного не приводит к потере точности. Он точно преобразуется из одинарной в удвоенную, и битовое сравнение двух значений работает.
Правильный ответ получен с наибольшим количеством голосов и проверен ответом на полдан. Это случай смешанной точности, и вам никогда не следует сравнивать на равных.
Почему не было показано в этом ответе. 0.7 не работает 1.0 работает. Почему 0,7 сбоя не было показано. Дублирующий вопрос 1.1 также терпит неудачу.
EDIT
Здесь можно вывести равные из проблемы, это уже другой вопрос, на который уже дан ответ, но это та же проблема, которая также имеет первоначальный шок "что за ...".
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, если бы я хотел округлить до 3-й цифры сверху, это было бы 12300000, но округлилось бы до следующей цифры 1235000, если цифра после 5 или больше, чем округление вверх. 5 - это 1/2 от 10, основание (десятичное число) в двоичном виде 1 равно 1/2 от основания, поэтому, если цифра после позиции, которую мы хотим округлить, равна 1, то округление в большую сторону не выполняется. Таким образом, для 0,7 мы не округлились, для 0,6 мы округлились.
И теперь легко увидеть, что
00110011001100110011010
конвертируется в двойную из-за (x <0,7) </p>
00110011001100110011010000000000....
больше
00110011001100110011001100110011....
Так что, не говоря уже об использовании равных, проблема все еще представляет себя 0,7 - двойная 0,7f - одиночная, операция повышается до максимальной точности, если они различаются.