5
<?php 
$x=PHP_INT_MAX; 
echo ((float)($x+1026)==(float)($x))?'EQUAL':'Not Equal'; 

Je sais que l'arithmétique en virgule flottante est pas exacte et $ x et $ x + 1 sont si proches qu'ils sont arrondis à la même valeur à virgule flottante et affiche la sortie sous la forme EQUAL si vous utilisez un nombre compris entre 1 et 1025, mais c'est seulement après avoir utilisé la valeur au-delà de 1025 que la sortie sera considérée comme «non égale». Je veux savoir pourquoi? Quelle est la raison derrière tout cela? Pourquoi seulement après 1025?Pourquoi deux variables float avec des valeurs PHP_INT_MAX sont les mêmes à moins que l'un d'entre eux est ajouté avec une valeur supérieure à 1025

+2

Vous devez commencer à regarder le (https [représentation au niveau binaire de flotteurs]: // en. wikipedia.org/wiki/Floating_point) et cela variera aussi selon que vous exécutez PHP –

+0

32 bits ou 64 bits quelle version de PHP avez-vous? avec mon test j'ai "pas égal" avec "$ x + 10" par exemple – mmm

+1

Jetez un oeil à [ce convertisseur] (http://www.h-schmidt.net/FloatConverter/IEEE754.html), ce qui vous permet pour voir la représentation flottante pour les différents nombres –

Répondre

4

Avec flotteur, votre hypothèse $x == $x + 1 est pas nécessairement vrai:

$x=2; 
echo ((float)($x+1)==(float)($x))?'EQUAL':'Not Equal'; 

cède "Different".

Dans le convertisseur lié dans les commentaires (http://www.h-schmidt.net/FloatConverter/IEEE754.html), vous pouvez reproduire cela. 0x40000000, la décimale 0x40000000, donne donne 0x40400000, donc ils sont en effet différents quand il s'agit de la représentation flottante IEEE754.

Considérant que, par exemple, la décimale 0.1 ne peut pas être représentée comme flottant: 0x3dcccccd, qui est 0.10000000149011612.

Quel est le nombre décimal 9223372036854775807? C'est 0x5f000000, qui est 9.223372E18, qui est 9223372180000000000.

Quelle est décimal 9223372036854775808 (PHP_MAX_INT + 1)? C'est aussi 0x5f000000.

Quelle est décimal 9223372036854776832 (PHP_MAX_INT + 1025)? C'est aussi 0x5f000000.

Quelle est décimal 9223372036854776833 (PHP_MAX_INT + 1026)? C'est aussi 0x5f000000.

Ils sont tous les mêmes. Considérant que, par exemple: décimal 9223373000000000000 (PHP_MAX_INT + 963145224193)?

C'est 0x5f000001, qui est 9.223373E18, qui est 9223373000000000000.

Maintenant, pourquoi:

((float)($x+1025)==(float)($x+1026))?'EQUAL':'Not Equal'; 

rendement "Different"?

Vous ajoutez un entier à PHP_MAX_INT.

$x=PHP_INT_MAX; 
$y=PHP_INT_MAX-1; 
$z=PHP_INT_MAX+1; 
var_dump($x); 
var_dump($y); 
var_dump($z); 

rendements:

int(9223372036854775807) 
int(9223372036854775806) 
float(9.2233720368548E+18) 

PHP convertit implicitement entiers trop gros pour flotter. Et c'est là que vous êtes fondamentalement perdu en interne PHP (du moins à mon avis), car à partir de là, vous ne saurez jamais ce qui va se passer (sans connaître les internes PHP, n'hésitez pas à me corriger, cependant).

Avis ceci:

$x=PHP_INT_MAX; 
$a=(float)($x+1025.0); // 1025 float 
$b=(float)($x+1026.0); // 1026 float 
$c=(float)($x+1025); // 1025 int 
$d=(float)($x+1026); // 1026 int 
var_dump($x); 
var_dump($a); 
var_dump($b); 
var_dump($c); 
var_dump($d); 
var_dump($a==$b); 
var_dump($a===$b); 
var_dump($c==$d); 
var_dump($c===$d); 

rendements:

int(9223372036854775807) 
float(9.2233720368548E+18) 
float(9.2233720368548E+18) 
float(9.2233720368548E+18) 
float(9.2233720368548E+18) 
bool(true) 
bool(true) 
bool(false) 
bool(false) 

Si vous ajoutez un entier ($x+1026) à PHP_MAX_INT, il est converti en flotter, et lorsque vous ajoutez un flotteur ($x+1026.0), il flotte aussi, bien sûr. Mais, évidemment, ils ne sont pas les mêmes en interne, voir les comparaisons ci-dessus.

Bottom line:

  • Ne pas comparer les flotteurs pour l'égalité
  • Faites attention à vos moulages; (float)($x+1026) est une addition entière, puis lancée pour flotter, tandis que (float)($x+1026.0) convertit $x pour flotter, puis ajoute le flotteur 1026.0, puis jette (en superflue) pour flotter.

Edit: en plus, voir: