Alles Falsche über den Float in PHP, das Sie wissen sollten (Alles Falsche über den Float in PHP)
PHP ist eine schwach typisierte Sprache, die nahtlos erforderlich ist Bei der transparenten impliziten Typkonvertierung verwendet PHP intern zval, um jede Art von Wert zu speichern. Die Struktur von zval ist wie folgt (5.2 als Beispiel):
struct _zval_struct { /* Variable information */ zvalue_value value; /* value */ zend_uint refcount; zend_uchar type; /* active type */ zend_uchar is_ref; };
In der obigen Struktur wird der tatsächliche Wert selbst von gespeichert zvalue_value Union. :
typedef union _zvalue_value { long lval; /* long value */ double dval; /* double value */ struct { char *val; int len; } str; HashTable *ht; /* hash table value */ zend_object_value obj; } zvalue_value;
Das heutige Thema konzentriert sich nur auf zwei Mitglieder, lval und dval. Wir müssen uns darüber im Klaren sein, dass long lval eine unbestimmte Länge hat, abhängig von der Wortlänge des Compilers und des Betriebssystems 32 Bit oder 64 Bit sein, und double dval (doppelte Genauigkeit) ist in IEEE 754 vorgeschrieben. Es hat eine feste Länge und muss 64 Bit betragen.
Bitte beachten Sie dies, wodurch einige PHP-Codes zu einer „nicht plattformunabhängigen“ Eigenschaft werden ". Unsere folgende Diskussion geht, sofern nicht anders angegeben, davon aus, dass long eine 64-Bit
IEEE 754-Gleitkomma-Zählmethode ist. Ich werde sie hier nicht zitieren. Wenn Sie interessiert sind, können Sie es selbst ausprobieren. Der entscheidende Punkt ist, dass die Mantisse von Double in 52 Bits gespeichert ist. Wenn man das versteckte 1 signifikante Bit mitzählt, beträgt die Gesamtzahl 53 Bits.
Hier stellt sich eine interessante Frage. vorausgesetzt, long ist 64 Bit):
long a = x; assert(a == (long)(double)a);
Entschuldigung, wenn der Wert von a in welchem Bereich liegt, kann behauptet werden, dass der obige Code erfolgreich ist? (Lassen Sie die Antwort am Ende des Artikels)
Jetzt kehren wir zum Thema PHP zurück. Bevor Sie ein Skript ausführen, müssen Sie zunächst das Skript lesen und analysieren. Dieser Vorgang umfasst beispielsweise auch die Zvalisierung der Literale im Skript:
<?php $a = 9223372036854775807; //64位有符号数最大值 $b = 9223372036854775808; //最大值+1 var_dump($a); var_dump($b);
Ausgabe:
int(9223372036854775807) float(9.22337203685E+18)
Mit anderen Worten: Während der lexikalischen Analysephase beurteilt PHP, ob ein Literalwert den langen Tabellenwertbereich des aktuellen Systems überschreitet. Wenn nicht, wird lval zum Speichern verwendet es, und zval wird IS_LONG sein, andernfalls verwenden Sie einfach dval, um es darzustellen, zval IS_FLOAT.
Wir müssen bei Werten, die größer als der größte ganzzahlige Wert sind, vorsichtig sein, da dies zu Genauigkeitsverlusten führen kann:
<?php $a = 9223372036854775807; $b = 9223372036854775808; var_dump($a === ($b - 1));
Die Ausgabe ist falsch.
Nun setzen wir die Diskussion vom Anfang fort. Wie bereits erwähnt, können die Ganzzahlen von PHP 32-Bit oder 64-Bit sein, daher wird entschieden, dass einige Codes normal ausgeführt werden können Auf 64-Bit-Systemen kann es aufgrund unsichtbarer Typkonvertierung zu einem Präzisionsverlust kommen, der dazu führt, dass der Code auf 32-Bit-Systemen nicht ordnungsgemäß ausgeführt wird.
Daher müssen wir diesen kritischen Wert berücksichtigen wurde in PHP definiert:
<?php echo PHP_INT_MAX; ?>
Aus Sicherheitsgründen sollten wir natürlich Zeichenfolgen verwenden, um große ganze Zahlen zu speichern, und mathematische Funktionsbibliotheken wie bcmath verwenden, um Berechnungen durchzuführen.
Darüber hinaus sollten wir Es gibt eine Schlüsselkonfiguration, die uns verwirren wird. Diese Konfiguration ist php.precision. Diese Konfiguration bestimmt, wie viele signifikante Bits PHP ausgibt, wenn es einen Float-Wert ausgibt Was ist der Maximalwert einer Ganzzahl, um sicherzustellen, dass die Genauigkeit nicht verloren geht, wenn sie in Float konvertiert und dann wieder in Long konvertiert wird?
Zum Beispiel wissen wir das für eine Ganzzahl seine binäre Darstellung ist 101. Nun verschieben wir zwei Bits nach rechts, um 1,01 zu werden, verwerfen das implizit signifikante Bit 1 des High-Bits und wir erhalten den im Double gespeicherten Binärwert von 5:
0/*符号位*/ 10000000001/*指数位*/ 0100000000000000000000000000000000000000000000000000
Die binäre Darstellung von 5, die im Mantissenteil gespeichert ist, wird in diesem Fall ohne Präzisionsverlust von double zurück in long konvertiert.
Wir wissen, dass double 52 Bits zur Darstellung der Mantisse verwendet Wenn man die implizite erste 1 zählt, ergibt sich eine Gesamtgenauigkeit von 53 Bits. Daraus kann geschlossen werden, dass diese Ganzzahl nicht an Genauigkeit verliert, wenn sie kleiner ist als:
2^53 - 1 == 9007199254740991; //牢记, 我们现在假设是64bits的long
Es erfolgt die Konvertierung von long->double->long-Werten
Empfohlen: „
PHP-TutorialDas obige ist der detaillierte Inhalt vonDinge, die Sie über PHP-Gleitkommazahlen wissen sollten. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!