2011-08-20 5 views
2

J'ai deux chiffres qui sont censés être égaux à retourner une différence, je ne fais pas de sens ...Comment deux nombres égaux ne soient pas égaux en PHP

La seule façon de pouvoir reproduire ce problème ici je devais bASE64_ENCODE mes tableaux,

voici le script:

essentiellement le script corrigera les numéros comme « 1 234,5 » à « 1234.5 » et fait des calculs, mais aux extrémités il retourne

  First Number: 4784.47 
      Second Number: 4784.47 
      Difference: 9.0949470177293E-13 

Je ne comprends tout simplement pas ????????


  $aa = 'YTo3OntpOjA7YToxMDp7czoxMToiRGVzY3JpcHRpb24iO3M6MTI6IkvDqWsgc3rDoW1vayI7czo2OiJQZXJpb2QiO3M6MTI6IjA4LjEwLTA4LjEwLiI7czo2OiJBbW91bnQiO3M6MToiMSI7czoxMjoiRHVyYXRpb25UaW1lIjtzOjc6IjA6MDQ6MDAiO3M6MTI6Ik5ldFVuaXRQcmljZSI7czo1OiIzNSwyMCI7czo5OiJOZXRBbW91bnQiO3M6NjoiMTQwLDgwIjtzOjEwOiJWQVRQZXJjZW50IjtzOjM6IjI1JSI7czozOiJWQVQiO3M6NToiMzUsMjAiO3M6MTE6Ikdyb3NzQW1vdW50IjtzOjY6IjE3NiwwMCI7czo4OiJJdGVtQ29kZSI7czo0OiJCTFVFIjt9aToxO2E6MTA6e3M6MTE6IkRlc2NyaXB0aW9uIjtzOjE3OiJCZWxmw7ZsZGkgaMOtdsOhcyI7czo2OiJQZXJpb2QiO3M6MTI6IjA3LjIyLTA4LjExLiI7czo2OiJBbW91bnQiO3M6MjoiMTIiO3M6MTI6IkR1cmF0aW9uVGltZSI7czo3OiIwOjIxOjQzIjtzOjEyOiJOZXRVbml0UHJpY2UiO3M6NToiMTUsMjAiO3M6OToiTmV0QW1vdW50IjtzOjY6IjMzMCwxMCI7czoxMDoiVkFUUGVyY2VudCI7czozOiIyNSUiO3M6MzoiVkFUIjtzOjU6IjgyLDUyIjtzOjExOiJHcm9zc0Ftb3VudCI7czo2OiI0MTIsNjIiO3M6ODoiSXRlbUNvZGUiO3M6ODoiRklYX0ZMQVQiO31pOjI7YToxMDp7czoxMToiRGVzY3JpcHRpb24iO3M6MjM6IkVnecOpYiBtb2JpbCBlZ3lzw6lnw6FyIjtzOjY6IlBlcmlvZCI7czoxMjoiMDcuMjEtMDguMTEuIjtzOjY6IkFtb3VudCI7czoyOiI1MCI7czoxMjoiRHVyYXRpb25UaW1lIjtzOjc6IjE6MDE6MzgiO3M6MTI6Ik5ldFVuaXRQcmljZSI7czo1OiIxNSwyMCI7czo5OiJOZXRBbW91bnQiO3M6NjoiOTM2LDgzIjtzOjEwOiJWQVRQZXJjZW50IjtzOjM6IjI1JSI7czozOiJWQVQiO3M6NjoiMjM0LDIxIjtzOjExOiJHcm9zc0Ftb3VudCI7czo4OiIxIDE3MSwwNCI7czo4OiJJdGVtQ29kZSI7czo4OiJPRkZfRkxBVCI7fWk6MzthOjEwOntzOjExOiJEZXNjcmlwdGlvbiI7czoxOToiVm9kYWZvbmUgZWd5c8OpZ8OhciI7czo2OiJQZXJpb2QiO3M6MTI6IjA3LjE1LTA4LjEyLiI7czo2OiJBbW91bnQiO3M6MjoiMjAiO3M6MTI6IkR1cmF0aW9uVGltZSI7czo3OiIwOjU0OjM3IjtzOjEyOiJOZXRVbml0UHJpY2UiO3M6NToiMTUsMjAiO3M6OToiTmV0QW1vdW50IjtzOjY6Ijc2MywwNSI7czoxMDoiVkFUUGVyY2VudCI7czozOiIyNSUiO3M6MzoiVkFUIjtzOjY6IjE5MCw3NiI7czoxMToiR3Jvc3NBbW91bnQiO3M6NjoiOTUzLDgxIjtzOjg6Ikl0ZW1Db2RlIjtzOjc6Ik9OX0ZMQVQiO31pOjQ7YToxMDp7czoxMToiRGVzY3JpcHRpb24iO3M6MTU6Ik5lbXpldGvDtnppIFNNUyI7czo2OiJQZXJpb2QiO3M6MTI6IjA3LjEzLTA4LjEzLiI7czo2OiJBbW91bnQiO3M6MjoiNDIiO3M6MTI6IkR1cmF0aW9uVGltZSI7czoxOiItIjtzOjEyOiJOZXRVbml0UHJpY2UiO3M6NToiMzAsNDAiO3M6OToiTmV0QW1vdW50IjtzOjg6IjEgMjc2LDgwIjtzOjEwOiJWQVRQZXJjZW50IjtzOjM6IjI1JSI7czozOiJWQVQiO3M6NjoiMzE5LDIwIjtzOjExOiJHcm9zc0Ftb3VudCI7czo4OiIxIDU5NiwwMCI7czo4OiJJdGVtQ29kZSI7czo3OiJTTVNfSU5UIjt9aTo1O2E6MTA6e3M6MTE6IkRlc2NyaXB0aW9uIjtzOjIzOiJTTVMgaMOhbMOzemF0b24ga8OtdsO8bCI7czo2OiJQZXJpb2QiO3M6MTI6IjA3LjI1LTA4LjExLiI7czo2OiJBbW91bnQiO3M6MjoiMTUiO3M6MTI6IkR1cmF0aW9uVGltZSI7czoxOiItIjtzOjEyOiJOZXRVbml0UHJpY2UiO3M6NToiMTUsMjAiO3M6OToiTmV0QW1vdW50IjtzOjY6IjIyOCwwMCI7czoxMDoiVkFUUGVyY2VudCI7czozOiIyNSUiO3M6MzoiVkFUIjtzOjU6IjU3LDAwIjtzOjExOiJHcm9zc0Ftb3VudCI7czo2OiIyODUsMDAiO3M6ODoiSXRlbUNvZGUiO3M6NzoiU01TX09GRiI7fWk6NjthOjEwOntzOjExOiJEZXNjcmlwdGlvbiI7czoyMjoiU01TIGjDoWzDs3phdG9uIGJlbMO8bCI7czo2OiJQZXJpb2QiO3M6MTI6IjA3LjE3LTA4LjEyLiI7czo2OiJBbW91bnQiO3M6MjoiMTUiO3M6MTI6IkR1cmF0aW9uVGltZSI7czoxOiItIjtzOjEyOiJOZXRVbml0UHJpY2UiO3M6NToiMTUsMjAiO3M6OToiTmV0QW1vdW50IjtzOjY6IjE1MiwwMCI7czoxMDoiVkFUUGVyY2VudCI7czozOiIyNSUiO3M6MzoiVkFUIjtzOjU6IjM4LDAwIjtzOjExOiJHcm9zc0Ftb3VudCI7czo2OiIxOTAsMDAiO3M6ODoiSXRlbUNvZGUiO3M6NjoiU01TX09OIjt9fQ=='; 

  $tt = 'YTozOntzOjE2OiJTdW1tYXJ5SXRlbU5ldHRvIjtzOjg6IjMgODI3LDU4IjtzOjE0OiJTdW1tYXJ5SXRlbVZBVCI7czo2OiI5NTYsODkiO3M6MTc6IlN1bW1hcnlJdGVtQnJ1dHRvIjtzOjg6IjQgNzg0LDQ3Ijt9'; 

  $a = unserialize(base64_decode($aa)); 
      $t = unserialize(base64_decode($tt)); 


      function calculate_call_fees($a,$t){ 

       $or_item = 0; 

       foreach($a as $k => $r) { 
        $or_item += fix_num($r['GrossAmount']); 
       }   

       $br = fix_num($t['SummaryItemBrutto']); 

       if($br>$or_item){ 
        $diff = $br-$or_item; 
       } else { 
        $diff = 0; 
       } 

       echo 'First Number: ' . $br.'<br/>'; 
       echo 'Second Number: ' . $or_item.'<br />'; 
       echo 'Difference: ' . $diff.'<br />'; 

       echo '<hr />'; 
       echo '<pre>'; 
       print_r($a); 
       echo '</pre>'; 
       echo '<hr />'; 
       echo '<pre>'; 
       print_r($t); 
       echo '</pre>';  

      } 

      function fix_num($n){ 
       return floatval(str_replace(Array(" ",","),array("","."),$n)); 
      } 

      calculate_call_fees($a,$t); 
+0

9.0949470177293E-13 est une ** petite ** différence minime. Avez-vous essayé d'utiliser === pour comparer les 2 nombres? – apscience

+0

la magie des mathématiques en virgule flottante: http://floating-point-gui.de/ –

+0

Les calculs de virgule flottante sont inexacts (avec perte). Ce n'est pas parce qu'ils s'impriment de la même façon qu'ils sont identiques dans leur représentation binaire (ce qui est ce que '==', cependant, essaie pour). – mario

Répondre

2

L'utilisation de la comparaison «égale» avec les nombres à virgule flottante est dangereuse en raison de la précision limitée du nombre à virgule flottante - vous risquez d'obtenir de petites différences en raison de l'arrondissement.

Au lieu de cela, si vous voulez voir si deux nombres à virgule flottante sont « les mêmes », juste voir si leur différence est inférieure à un certain seuil:

if(abs($a - $b) < 0.00000001) { 
    // a and b are "equal" 
} 
+0

hmm. merci, je ne savais pas à ce sujet. mais si j'utilise "if ($ br> fix_num ($ or_item))", il retourne zéro, bien que "fix_num" ne fasse rien de spécial ???? cela signifie-t-il que chaque calcul que je fais avec des flotteurs souffrira de petites différences? – shar

+0

Si vous utilisez ceci, assurez-vous d'utiliser la fonction abs(), dans le cas où la valeur de $ b est supérieure à $ a, comme ceci: if (abs ($ a- $ b) <.0000001) {... suppose que les deux valeurs ont le même signe. –

1

Il est non seulement PHP. Il existe un problème général de représentation des nombres fractionnaires dans l'ordinateur. Il est sujet à différents types de débordements, sous-flux, problèmes de précision et ainsi de suite. PHP's manual jeter un peu de lumière sur le sujet.

La règle générale - si vous demande de deux « semblent-égaux » nombres à garantir l'égalité - ne pas utiliser flottante types de données de points (float, double), mais point fixe (décimal, numérique)

+0

alors je devrais convertir mes flotteurs en décimal? – shar

Questions connexes