Domanda

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

Perché il not equal uscita?

Perché accade questo?

È stato utile?

Soluzione

Questo accade perché nella sua dichiarazione

  if(f == 0.7)

il 0,7 è considerato un doppio. Prova 0.7f per garantire il valore viene trattato come un float:

  if(f == 0.7f)

Ma, come Michael suggerito nei commenti qui sotto non si dovrebbe mai verificare l'uguaglianza esatta dei valori in virgola mobile.

Altri suggerimenti

Questa risposta per completare quelli esistenti: si noti che 0.7 non è rappresentabile esattamente sia come un galleggiante (o come un doppio). Se è stata rappresentata esattamente, allora non ci sarebbe alcuna perdita di informazioni durante la conversione di galleggiare e poi di nuovo al doppio, e non avrebbe questo problema.

Si potrebbe anche sostenere che ci dovrebbe essere un avviso del compilatore per le costanti in virgola mobile letterali che non può essere rappresentato esattamente, in particolare quando lo standard è così confusa per quanto riguarda se l'arrotondamento sarà effettuato in fase di esecuzione in modalità che ha stato impostato come quel tempo o al momento della compilazione in un'altra modalità di arrotondamento.

Tutti i numeri non interi che possono essere rappresentati esattamente avere 5 come la loro ultima cifra decimale. Purtroppo, il contrario non è vero: alcuni numeri sono 5 come la loro ultima cifra decimale e non può essere rappresentato esattamente. I piccoli numeri interi possono essere rappresentati esattamente, e la divisione per una potenza di 2 trasforma un numero che può essere rappresentato in un altro che può essere rappresentato, fino a quando non si immette nel regno dei numeri denormalizzati.

Prima di tutto lascia guardare dentro il numero float. Prendo 0.1f è 4 byte di lunghezza (binary32), in esadecimale è
3D CC CC CD .
Entro la standart IEEE 754 per convertirlo in decimale che dobbiamo fare in questo modo:

 entrare descrizione dell'immagine qui
In 3D binario CC CC CD è
0 01111011 1001100 11001100 11001101
qui prima cifra è un po 'segno. 0 mezzi (-1) ^ 0 che il nostro numero è positivo.
Secondi 8 bit è un esponente. In binario è 01.111.011 - in decimale 123. Ma il vero esponente è 123-127 (sempre 127) = -4 , è media abbiamo bisogno di moltiplicare il numero avremo per 2 ^ (- 4 ).
Gli ultimi 23 byte è la precisione significando. C'è il primo bit moltiplichiamo per 1 / (2 ^ 1) (0,5), secondo per 1 / (2 ^ 2) (0,25) e così via. Ecco quello che otteniamo:

 entrare descrizione dell'immagine qui entrare image description qui

Abbiamo bisogno di aggiungere tutti i numeri (potenza di 2) e aggiungere ad essa 1 (sempre 1, da standart). È
1,60000002384185791015625
Ora cerchiamo di moltiplicare questo numero per 2 ^ (- 4), è da Exponent. Abbiamo il numero appena sopra devide da 2 a quattro tempi:
0,100000001490116119384765625
Ho usato MS Calculator
**

Ora la seconda parte. Conversione da decimale a binario.

**
Prendo il numero 0.1
E proprio agio, perché non v'è alcuna parte intera. Primo bit di segno - è 0. Esponente e significando la precisione io calcolare ora. La logica è moltiplicare per 2 numero intero (0,1 * 2 = 0.2) e se è superiore a 1 sottrarre e continuare.
entrare image description qui
E il numero è 0,00011001100110011001100110011, standart dice che dobbiamo spostamento a sinistra prima di arrivare 1. (qualcosa). Come vedete abbiamo bisogno di 4 turni, da questo numero calcolo esponente (127-4 = 123 ). E la precisione significando ora è
10011001100110011001100 (e ci si perde bit).
Ora il numero intero. bit di segno 0 esponente è 123 ( 01.111.011 ) e significando la precisione è 10011001100110011001100 e complesso è
00111101110011001100110011001100 confrontiamo con quelli che abbiamo da precedente capitolo
00111101110011001100110011001101
Come si vede la dura bit non sono uguali. E 'perché ho troncare il numero. La CPU e compilatore sa che il è qualcosa dopo significando precisione non può tenere e basta impostare l'ultimo bit a 1.

Il problema si sta affrontando è, come altri commentatori hanno notato, che è generalmente pericoloso per verificare l'equivalenza esatta tra carri allegorici, come errori di inizializzazione, o errori di arrotondamento nei calcoli può introdurre piccole differenze che causeranno l'operatore == per return false.

Una pratica migliore è quello di fare qualcosa di simile

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

Supponendo che FLT_EPSILON è stato definito come un livello sufficientemente piccolo valore float per la piattaforma.

Dal momento che gli errori di arrotondamento o di inizializzazione saranno difficilmente superano il valore di FLT_EPSILON, questo vi darà il test di equivalenza affidabile che stai cercando.

Un sacco di risposte giro per il web fanno l'errore di guardare la differenza abosulute tra i numeri in virgola mobile, questo è valido solo per casi particolari, il modo robusto è quello di guardare la differenza relativa, come in seguito:

      // 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;

        }

Un altro interrogativo accanto esatto era legato a questa quindi la risposta anni di ritardo. Non penso che le risposte di cui sopra sono completi.

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

Perché ha fun3 e fun4 restituire uno e non gli altri? perché funziona fun5?

Si tratta del linguaggio. La lingua dice che 0.7 è un doppio se non si utilizza questa sintassi 0.7f, allora è una sola. Quindi

  float x=0.7;

doppio 0.7 viene convertito in un singolo e memorizzato in x.

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

La lingua dice che dobbiamo promuovere la maggiore precisione in modo che il singolo di x viene convertito in un letto matrimoniale e confronto con la doppia 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

singolo 3f333333 doppia 3fe6666666666666

Come Alexandr ha sottolineato che se la risposta rimane IEEE 754 è un singolo

  

seeeeeeeefffffffffffffffffffffff

E doppia è

  

seeeeeeeeeeeffffffffffffffffffffffffffffffffffffffffffffffffffff

con 52 bit di frazione piuttosto che il 23 quell'unico trovi.

00111111001100110011... single
001111111110011001100110... double

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

Proprio come 1/3 ° in base 10 è ,3333,333 mila ... per sempre. Abbiamo un pattern ripetuto qui 0110

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

E qui è la risposta.

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

x contiene 01100110011001100110011 come sua frazione, quando questo viene convertito indietro per raddoppiare la frazione è

01100110011001100110011000000000....

, che non è uguale a

01100110011001100110011001100110...

ma qui

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

che la promozione non accade gli stessi modelli di bit sono confrontati tra loro.

Perché il 1,0 lavoro?

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

In entrambi i casi la frazione è tutti zeri. Quindi, la conversione da doppia a singola a doppia v'è alcuna perdita di precisione. Converte da singolo a doppio esattamente e il confronto bit dei due valori funziona.

Il più alto votato e controllato dalla risposta Halfdan è la risposta corretta, questo è un caso di precisione mista e non si dovrebbe mai fare di uguale confronto.

L'intrattenimento non era il motivo per cui indicato in quella risposta. 0.7 fallisce 1.0 opere. Perché non riescono 0.7 non era indicata. Una domanda duplicato 1.1 non riesce pure.


Modifica

I uguali possono essere prese fuori il problema qui, è una questione diversa che è già stato risposto, ma è lo stesso problema e ha anche la "ciò che il ..." shock iniziale.

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

Perché uno spettacolo come inferiore e l'altro non inferiore a? Quando dovrebbero essere uguali.

Dall'alto sappiamo la storia 0.7.

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

01100110011001100110011000000000....

è inferiore.

01100110011001100110011001100110...

0.6 è un diverso modello di ripetizione 0011 anziché 0110.

ma quando convertito da un letto ad una sola o in generale quando rappresentata come un singolo IEEE 754.

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

IEEE 754 utilizza modalità di arrotondamento, arrotondare, arrotondare o rotonda a zero. I compilatori tendono per arrotondare per difetto. Se vi ricordate l'arrotondamento in grado di scuola 12345678 se volevo arrotondare alla 3a cifra dall'alto sarebbe 12300000, ma intorno alla cifra successiva 1.235.000 se la cifra dopo è 5 o maggiore di arrotondare. 5 è 1/2 del 10 della base (decimale) in binario 1 è 1/2 della base, quindi se la cifra dopo la posizione che vogliamo round è 1 poi arrotondare il resto Dont. Così, per 0,7 non abbiamo arrotondare, per 0,6 facciamo arrotondare.

E ora è facile vedere che

00110011001100110011010

convertito in un letto a causa di (x <0,7)

00110011001100110011010000000000....

è maggiore di

00110011001100110011001100110011....

Quindi, senza dover parlare con uguale il problema si presenta ancora 0.7 è doppia 0.7f è single, l'operazione viene promosso la massima precisione se differiscono.

Considerate questo:

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

se (0,7> a) qui è una variabile float e 0.7 è un doppio costante. Il doppio 0.7 costante è maggiore della variabile float a. Da qui la se la condizione è soddisfatta e la stampa 'Hi'

Esempio:

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

Output:
0,7 miliardi ,6999,999881 millions

Se si cambia tipo di dati f a doppia , che sarà stampare uguale , questo è perché le costanti in virgola mobile memorizzati in doppia e non galleggianti in lungo , doppia precisione è alta e galleggiante è meno precisa, doppio valore memorizzato in 64 bit valore binario e float memorizzati in 32 bit binari, sarà completamente chiaro se si vede il metodo di galleggiare conversione numeri in virgola alla conversione binaria.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top