Pergunta

float f = 0.7;
if( f == 0.7 )
    printf("equal");
else
    printf("not equal");

Por que o not equal saída?

Por que isso acontece?

Foi útil?

Solução

Isso acontece porque, em sua declaração

  if(f == 0.7)

a 0,7 é tratado como uma dupla. Tente 0.7f para garantir o valor é tratado como um float:

  if(f == 0.7f)

Mas, como Michael sugeriu nos comentários abaixo você nunca deve teste de igualdade exata de valores de ponto flutuante.

Outras dicas

Esta resposta para complementar os já existentes: nota que 0,7 não é representável exatamente quer como um float (ou como um duplo). Se ele foi representado exatamente, então não haveria perda de informação ao converter a flutuar e depois voltar para o dobro, e você não teria esse problema.

Pode até ser argumentado que deveria haver um aviso do compilador para constantes de ponto flutuante literais que não podem ser representados exatamente, especialmente quando o padrão é tão confuso sobre se o arredondamento será feito em tempo de execução no modo que tem foi definido como o tempo ou em tempo de compilação em outro modo de arredondamento.

Todos os números não-inteiros que podem ser representados têm exatamente 5 como seu último dígito decimal. Infelizmente, o inverso não é verdadeiro: alguns números têm 5 como seu último dígito decimal e não pode ser representado exatamente. Pequenos números inteiros podem ser representados exatamente, e divisão por uma potência de 2 Transforma um número que pode ser representado em outro que pode ser representada, desde que você não entrar no reino de números desnormalizados.

Em primeiro lugar número dentro de olhar flutuador let. Eu tomo 0.1f é de 4 bytes de comprimento (binary32), em hexadecimal é
CD CC CC 3D .
pelo Standart IEEE 754 para convertê-lo para decimal devemos fazer assim:

 enter descrição da imagem aqui
Em binário 3D CC CC CD é
0 01111011 1001100 11001100 11001101
aqui primeiro dígito é um bit de sinal. 0 meio (-1) ^ 0 que o nosso número é positivo.
Segundo 8 bits é um expoente. Em binário é 01111011 - em decimal 123. Mas o verdadeiro expoente é 123-127 (sempre 127) = -4 , é necessário que queremos dizer para multiplicar o número que terá por 2 ^ (- 4 ).
Os últimos 23 bytes é a precisão significando. Há o primeiro bit que multiplicar por 1 / (2 ^ 1) (0,5), segundo por 1 / (2 ^ 2) (0,25) e assim por diante. Aqui o que temos:


 enter descrição da imagem aqui enter descrição da imagem aqui

Precisamos adicionar todos os números (potência de 2) e adicionar-lhe 1 (sempre 1, por Standart). É
1,60000002384185791015625
Agora vamos multiplicar esse número por 2 ^ (- 4), é de Exponent. Nós número apenas Devide acima por 2 quatro vezes:
0,100000001490116119384765625
I utilizado MS calculadora
**

Agora a segunda parte. Convertendo de decimal para binário.

**
eu tomo o número de 0,1
Ele facilidade porque não há nenhuma parte inteira. Primeiro bit de sinal - é 0. precisão e expoente significando que irá calcular agora. A lógica é multiplicar por dois o número inteiro (0,1 * 2 = 0,2) e se for maior do que um substrato e continuar.
enter descrição da imagem aqui
E o número é ,00011001100110011001100110011, Standart diz que devemos desvio para a esquerda antes de chegarmos 1. (algo). Como você vê que precisamos 4 turnos, a partir deste número cálculo Exponent (127-4 = 123 ). Ea precisão significando agora é
10011001100110011001100 (e não é perdido bits).
Agora o número inteiro. Bit de sinal 0 Exponent é 123 ( 01111011 ) e precisão significand é 10011001100110011001100 e toda é
00111101110011001100110011001100 Vamos compará-lo com aqueles que têm a partir do capítulo anterior
00111101110011001100110011001101
Como você vê a dura pouco não são iguais. É porque eu truncar o número. A CPU e compilador sabe que o é algo depois precisão significando não pode segurar e apenas definir o último bit a 1.

O problema que você está enfrentando é, como outros comentadores notaram, que geralmente é inseguro para teste de equivalência exata entre carros alegóricos, como erros de inicialização, ou erros de arredondamento nos cálculos podem apresentar pequenas diferenças que fará com que o operador == para return false.

A melhor prática é fazer algo como

float f = 0.7;
if( fabs(f - 0.7) < FLT_EPSILON )
    printf("equal");
else
    printf("not equal");

Assumindo que FLT_EPSILON tem sido definida como um valor float adequadamente pequena para sua plataforma.

Uma vez que o arredondamento ou erros de inicialização será pouco provável que exceder o valor das FLT_EPSILON, isso vai lhe dar o teste de equivalência de confiança que você está procurando.

Um monte de respostas em torno da web cometem o erro de olhar para a diferença abosulute entre os números de ponto flutuante, isto é válido apenas para casos especiais, a forma robusta é olhar para a diferença relativa como na abaixo:

      // Floating point comparison:

        bool CheckFP32Equal(float referenceValue, float value)
        {
           const float fp32_epsilon = float(1E-7);
           float abs_diff = std::abs(referenceValue - value);

           // Both identical zero is a special case
           if( referenceValue==0.0f && value == 0.0f)
              return true;

           float rel_diff = abs_diff / std::max(std::abs(referenceValue) , std::abs(value) ); 

           if(rel_diff < fp32_epsilon)
                 return true;
           else 
                 return false;

        }

Outra pergunta exata perto estava ligado a este, portanto, o ano resposta tardia. Eu não acho que as respostas acima estão completas.

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

Por que fun3 e um fun4 retorno e não os outros? porque funciona fun5?

É sobre a língua. A linguagem diz que 0,7 é um duplo a menos que você use este 0.7f sintaxe, então é um único. Então

  float x=0.7;

o dobro 0,7 é convertido a um único e armazenado em x.

  if(x==0.7) return(1);

A linguagem diz que temos de promover a maior precisão de modo que o único em x é convertido para um casal e comparados com a dupla 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 única double 3fe6666666666666

Como Alexandr apontou, se essa resposta permanece IEEE 754 um único é

seeeeeeeefffffffffffffffffffffff

E duplo é

seeeeeeeeeeeffffffffffffffffffffffffffffffffffffffffffffffffffff

com 52 bits de fracção em vez de a 23 que tem único.

00111111001100110011... single
001111111110011001100110... double

0 01111110 01100110011... single
0 01111111110 01100110011... double

Assim como 1/3 na base 10 é 0,3333333 ... para sempre. Temos um padrão de repetição aqui 0110

01100110011001100110011 single, 23 bits
01100110011001100110011001100110.... double 52 bits.

E aqui está a resposta.

  if(x==0.7) return(1);

x contém 01100110011001100110011 como sua fração, quando isso fica para trás convertido para dobrar a fração for

01100110011001100110011000000000....

que não é igual a

01100110011001100110011001100110...

mas aqui

  if(x==0.7f) return(1);

acontecer que does not promoção os mesmos padrões de bits são comparados uns com os outros.

Por que 1.0 trabalho?

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...

Em ambos os casos a fração for todos os zeros. Então conversão de dupla para simples para duplo não há nenhuma perda de precisão. Ele converte de simples para duplo exatamente ea comparação dos dois valores obras bit.

O mais votado e verificado resposta por Halfdan é a resposta correta, este é um caso de precisão misturados e você nunca deve fazer um igual comparação.

O porquê não era mostrado nessa resposta. 0,7 falhar 1.0 funciona. Por que 0,7 falhar não era mostrado. Uma questão duplicado 1,1 falhar bem.


Editar

Os iguais podem ser retirados do problema aqui, é uma questão diferente, que já foi respondida, mas é o mesmo problema e também tem o "o que o ..." choque inicial.

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

Por que um show como menos do que eo outro não menos do que? Quando eles devem ser iguais.

De cima nós conhecemos a história 0,7.

01100110011001100110011 single, 23 bits
01100110011001100110011001100110.... double 52 bits.

01100110011001100110011000000000....

é inferior a.

01100110011001100110011001100110...

0.6 é um teste padrão de repetição diferentes 0011 em vez de 0110.

mas quando convertido a partir de um duplo a um único ou em geral quando representada como um único IEEE 754.

00110011001100110011001100110011.... double 52 bits.
00110011001100110011001 is NOT the fraction for single
00110011001100110011010 IS the fraction for single

IEEE 754 usa o arredondamento modos, até rodada, para baixo redonda ou redondas para zero. Compiladores tendem a arredondar para cima por padrão. Se você se lembrar de arredondamento na escola 12345678 se eu queria volta para o terceiro dígito do topo seria 12.300.000 mas volta para o próximo dígito 1.235.000 se o dígito depois é 5 ou superior, em seguida, até round. 5 é 1/2 de 10 de base (Decimal) em binário 1 é 1/2 da base por isso, se o dígito depois da posição que queremos rodada é de 1 em seguida, volta-se outra coisa não faça. Assim, para 0,7 não tivemos até rodada, para 0,6 fazemos até round.

E agora, é fácil ver que

00110011001100110011010

convertido para um duplo devido a (x <0,7)

00110011001100110011010000000000....

é maior do que

00110011001100110011001100110011....

Assim, sem ter que falar sobre o uso iguala o problema ainda se apresenta 0,7 é o dobro 0.7f é único, a operação é promovido para a mais alta precisão se forem diferentes.

Considere o seguinte:

int main()
{
    float a = 0.7;
    if(0.7 > a)
        printf("Hi\n");
    else
        printf("Hello\n");
    return 0;
}

se (0,7> a) aqui uma é uma variável flutuador e 0.7 é uma constante dupla. A constante 0.7 dupla é maior do que a variável flutuador um. Daí a se a condição for satisfeita e imprime 'Hi'

Exemplo:

int main()
{
    float a=0.7;
    printf("%.10f %.10f\n",0.7, a);
    return 0;
}

Output:
0,7000000000 0,6999999881

Se você alterar tipo de dados f para duplo , ele vai imprimir igualar , Isto porque constantes em ponto flutuante armazenado em duplo e não flutuando no longo , dupla precisão é alta e flutuador tem menos preciso, duplo valor armazenado em /> armazenado em 32 binário bit, vai ser completamente claro, se você ver o método de flutuar conversão números de ponto à conversão binário.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top