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

wiem zmiennoprzecinkowych arytmetyka nie jest dokładna i $ x i $ x + 1 są tak blisko siebie, że są one zaokrąglane do tej samej wartości zmiennoprzecinkowej i pokazuje wynik jako EQUAL, jeśli użyjesz dowolnej liczby od 1 do 1025, ale tylko wtedy, gdy użyjesz wartości powyżej 1025, zacznie ona podawać wynik jako "Nie równy". Chcę wiedzieć dlaczego? Jaki jest tego powód? Dlaczego dopiero po 1025?Dlaczego dwie zmienne pływak z wartościami PHP_INT_MAX są takie same, chyba że jeden z nich dodaje się wartość większą niż 1025

+2

Trzeba zacząć patrząc na [poziomie nieco reprezentacji pływaków] (https: // en. wikipedia.org/wiki/Floating_point) i to będzie się różnić w zależności od tego, czy używasz 32-bitowej, czy 64-bitowej wersji PHP –

+0

, którą wersję PHP posiadasz? z moim testem mam "nie równy" z "$ x + 10" na przykład – mmm

+1

Spójrz na [ten konwerter] (http://www.h-schmidt.net/FloatConverter/IEEE754.html), który pozwala aby zobaczyć reprezentację zmiennoprzecinkową dla różnych numerów –

Odpowiedz

4

z pływakiem, twój założenie $x == $x + 1 niekoniecznie jest prawdą:

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

daje "nie równa się".

W konwerterze połączonym w komentarzach (http://www.h-schmidt.net/FloatConverter/IEEE754.html) można go odtworzyć. dziesiętny 2.0 daje 0x40000000, dziesiętny 3.0 daje 0x40400000, więc są one rzeczywiście różne, jeśli chodzi o reprezentację float IEEE754.

Podczas gdy np. Dziesiętny 0.1 nie może być reprezentowany jako zmienny: 0x3dcccccd, który jest 0.10000000149011612.

Jaki jest dziesiętny 9223372036854775807? To jest 0x5f000000, która jest 9.223372E18, która jest 9223372180000000000.

Jaki jest dziesiętny 9223372036854775808 (PHP_MAX_INT + 1)? To także 0x5f000000.

Co to jest dziesiętna 9223372036854776832 (PHP_MAX_INT + 1025)? To także 0x5f000000.

Jaki jest dziesiętny 9223372036854776833 (PHP_MAX_INT + 1026)? To także 0x5f000000.

Wszystkie są takie same.

Natomiast np .: dziesiętnie 9223373000000000000 (PHP_MAX_INT + 963145224193)? To jest 0x5f000001, czyli 9.223373E18, czyli 9223373000000000000.

Teraz, dlaczego:

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

plon "nie równa się"?

Dodajesz liczbę całkowitą do 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); 

plony:

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

PHP niejawnie konwertuje liczby całkowite zbyt duże, aby pływaka. I w tym przypadku zagubiłeś się w wewnętrznych aplikacjach PHP (przynajmniej moim zdaniem), ponieważ od tego momentu nigdy się nie dowiesz, co się stanie (nie znając wewnętrznych elementów PHP, nie krępuj się jednak poprawić).

odnotować to:

$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); 

Wydajność:

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) 

Po dodaniu całkowitą ($x+1026) do PHP_MAX_INT przekształcany jest do pływaka, a po dodaniu do pływaka ($x+1026.0) Oczywiście jest to również float. Ale, oczywiście, nie są one takie same wewnętrznie, patrz porównania powyżej.

Konkluzja:

  • Nie porównuj pływaków na rzecz równości
  • Bądź ostrożny o swoich odlewów; (float)($x+1026) jest dodawaniem całkowitym, a następnie odlewane do postaci pływającej, natomiast (float)($x+1026.0) przekształca $x w zmienną, następnie dodaje zmienną 1026.0, a następnie rzuca (zbytecznie), aby unosić się w powietrzu.

Edit: dodatkowo, patrz: