Question

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

Pourquoi le not equal de sortie?

Pourquoi cela?

Était-ce utile?

La solution

Cela se produit parce que dans votre déclaration

  if(f == 0.7)

0,7 est considérée comme une double. Essayez 0.7f pour assurer la valeur est traitée comme un flotteur:

  if(f == 0.7f)

Mais comme Michael a suggéré dans les commentaires ci-dessous vous ne devriez jamais tester l'égalité exacte des valeurs à virgule flottante.

Autres conseils

Cette réponse pour compléter ceux qui existent déjà: noter que 0,7 est représentable pas exactement soit comme un flotteur (ou double). Si elle était représentée exactement, alors il n'y aurait pas de perte d'information lors de la conversion de flotter, puis de nouveau doubler, et vous n'auriez pas ce problème.

On pourrait même dire qu'il devrait y avoir un compilateur d'avertissement pour les constantes en virgule flottante littéral qui ne peut pas être représenté exactement, en particulier lorsque la norme est si floue quant à savoir si l'arrondi sera effectué au moment de l'exécution dans le mode qui a été fixé comme temps que ou au moment de la compilation dans un autre mode d'arrondi.

Tous les nombres non entiers qui peuvent être représentés exactement ont 5 que leur dernier chiffre décimal. Malheureusement, l'inverse est pas vrai: certains chiffres ont 5 leur dernier chiffre décimal et ne peuvent pas être représentés exactement. Les petits entiers peuvent tous être représentés exactement, et la division par une puissance de 2 transforme un nombre qui peut être représenté dans un autre qui peut être représenté, tant que vous ne saisissez pas le royaume des nombres dénormalisés.

Tout d'abord laisser regarder à l'intérieur numéro de flotteur. Je prends 0.1f est de 4 octets de long (binary32), dans l'hexagone, il est
3D CC CC CD .
par le standart IEEE 754 pour le convertir en décimal que nous devons faire comme ceci:

 entrer image description ici
En 3D binaire CC CC CD est
0 01111011 1001100 11001100 11001101 ici premier chiffre est un bit de signe. 0 signifie (-1) ^ 0 que notre nombre est positif.
Deuxième 8 bits est un Exponent. En binaire, il est 01111011 - en décimal 123. Mais le vrai Exponent est 123-127 (toujours 127) = -4 , il est à dire que nous devons multiplier le nombre que nous obtiendrons par 2 ^ (- 4 ).
Les 23 derniers octets est la précision Signifiant. Là, le premier bit on multiplie par 1 / (2 ^ 1) (0,5), d'autre part par 1 / (2 ^ 2) (0,25) et ainsi de suite. Voici ce que nous obtenons:

 entrer image description ici entrer la description d'image ici

Nous devons ajouter tous les nombres (puissance de 2) et y ajouter 1 (toujours 1, par Standart). Il est
1,60000002384185791015625
Maintenant, nous allons multiplier ce nombre par 2 ^ (- 4), il est de Exponent. Nous comptons simplement Devide ci-dessus par 2 quatre temps:
0,100000001490116119384765625
Je MS Calculator
**

Maintenant la deuxième partie. Conversion de décimal en binaire.

**
Je prends le numéro 0.1
Il facilité parce qu'il n'y a pas de partie entière. bit premier signe - il est 0. Et Exponent Signifiant précision je calculer maintenant. La logique est multiplié par 2 nombre entier (0,1 * 2 = 0,2) et si elle est plus grand que 1 et de soustraction continue.
entrer la description d'image ici
Et le nombre est ,00011001100110011001100110011, Standart dit que nous devons passer à gauche avant d'arriver 1. (quelque chose). Comment vous voyez nous avons besoin de 4 quarts de travail, de ce nombre calcul Exponent (127-4 = 123 ). Et la précision Signifiant est maintenant
10011001100110011001100 (et il est perdu bits).
Maintenant, le nombre entier. bit de signe 0 Exponent est 123 ( 01111011 ) et Signifiant précision est 10011001100110011001100 et il est tout
00111101110011001100110011001100 comparons avec ceux que nous avons du chapitre précédent
00111101110011001100110011001101 Comme vous le voyez le bit dure ne sont pas égaux. Il est parce que je tronque le nombre. La CPU et le compilateur savent que la précision est quelque chose après Signifiant ne peut pas tenir et mettre juste le dernier bit à 1.

Le problème que vous êtes confronté est, comme d'autres commentateurs l'ont noté, qu'il est généralement dangereux pour tester l'équivalence exacte entre les flotteurs, les erreurs d'initialisation ou des erreurs d'arrondi dans les calculs peuvent présenter des différences mineures qui causeront l'opérateur == pour return false.

Une meilleure pratique consiste à faire quelque chose comme

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

En supposant que FLT_EPSILON a été définie comme une valeur flottante appropriée pour votre petite plate-forme.

Étant donné que les erreurs d'arrondi ou l'initialisation est peu susceptible de dépasser la valeur de FLT_EPSILON, cela vous donnera le test d'équivalence fiable que vous recherchez.

Beaucoup de réponses sur le web font l'erreur de regarder la différence abosulute entre nombres à virgule flottante, ceci est valable uniquement pour les cas particuliers, la façon robuste est de regarder la différence relative comme ci-dessous:

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

        }

Une autre question exacte près était liée à celle-ci ainsi la réponse tardive des années. Je ne pense pas que les réponses ci-dessus sont complètes.

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

Pourquoi est-ce fun3 et fun4 retourner l'un et pas les autres? Pourquoi fonctionne-t-fun5?

Il est de la langue. La langue dit que 0,7 est une double sauf si vous utilisez cette syntaxe 0.7f alors il est un seul. Donc,

  float x=0.7;

la double 0,7 est convertie en un seul et stocké dans x.

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

La langue dit que nous devons promouvoir la plus grande précision de sorte que la seule en x est converti en un double et par rapport à la double 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

simple 3f333333 deux 3fe6666666666666

Comme Alexandr a si cette réponse reste IEEE 754 est un

  

seeeeeeeefffffffffffffffffffffff

double est

  

seeeeeeeeeeeffffffffffffffffffffffffffffffffffffffffffffffffffff

avec 52 bits de fraction plutôt que le 23 qui unique a.

00111111001100110011... single
001111111110011001100110... double

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

Tout comme 1/3 dans la base 10 est 0,3333333 ... pour toujours. Nous avons un motif répétitif ici 0110

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

Et voici la réponse.

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

x contient 01100110011001100110011 que sa fraction, lorsque cela est converti en arrière doubler la fraction est

01100110011001100110011000000000....

qui ne soit pas égal à

01100110011001100110011001100110...

ici

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

qui ne marche pas de promotion se produire les mêmes modèles binaires sont comparés entre eux.

Pourquoi 1,0 travail?

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

Dans les deux cas, la fraction est des zéros. Ainsi, la conversion de double en simple au double, il n'y a aucune perte de précision. Il convertit du simple au double exactement et la comparaison binaire des deux valeurs fonctionne.

Le plus haut voté et vérifié par réponse Halfdan est la bonne réponse, c'est un cas de précision mixte et vous ne devriez jamais faire une comparaison égale.

Le pourquoi était pas montré dans cette réponse. 0,7 échoue 1.0 fonctionne. Pourquoi 0,7 échec était pas représenté. Une double question 1.1 échoue aussi.


EDIT

Les égaux peuvent être retirés du problème ici, il est une autre question qui a déjà été répondu, mais il est le même problème et a également la « ce que le ... » choc initial.

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

Pourquoi un spectacle comme moins et l'autre au moins? Quand ils doivent être égaux.

De là-haut, nous connaissons l'histoire 0,7.

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

01100110011001100110011000000000....

est inférieur.

01100110011001100110011001100110...

0,6 est un motif répétitif différent 0011 au lieu de 0110.

mais lorsqu'il est converti à partir d'un double à un seul ou en général lorsqu'il est représenté comme une seule IEEE 754.

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

IEEE 754 utilise les modes d'arrondi, arrondir, arrondir ou rond à zéro. Compilateurs ont tendance à arrondir par défaut. Si vous vous souvenez dans l'arrondissement école primaire 12345678 si je voulais arrondir au 3ème chiffre du haut, il serait 12300000, mais tour à l'autre chiffre 1.235.000 si le chiffre après est de 5 ou plus arrondir ensuite. 5 est 1/2 de la base 10 (décimal) en binaire 1 est 1/2 de la base, donc si le chiffre après la position que nous voulons arrondir est 1 tour ensuite d'autre Do not. Donc, pour nous ne avons pas 0,7 arrondissons, pour 0,6 nous n'arrondissons.

Et il est maintenant facile de voir que

00110011001100110011010

converti en une double raison de (x <0,7)

00110011001100110011010000000000....

est supérieur à

00110011001100110011001100110011....

Alors, sans avoir à parler à l'aide est égale à la question se présente encore 0,7 est le double 0.7f est simple, l'opération est promu la plus haute précision si elles diffèrent.

Considérez ceci:

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

si (0,7> a) ici a est une variable flottante et 0.7 est une double constante. La double 0.7 constante est supérieure à la variable flottante a. D'où la condition est satisfaite si et il imprime 'Hi'

Exemple:

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

Sortie: 0,7000000000 0,6999999881

Si vous changez de type de données f deux , il va imprimer égale , Ceci est parce que les constantes de virgule flottante stockées dans deux et non flottant dans longue , double précision est élevée et le flotteur a moins de valeur précise, double stocké dans 64 bit valeur binaire et le flotteur stocké dans 32 binaire, il sera tout à fait clair si vous voyez la méthode des nombres à virgule flottante conversion à la conversion binaire.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top