PHP の float について知っておくべきすべての「偽り」
PHP は弱い型指定言語です。そのような機能にはシームレスで透過的な暗黙的な型変換が必要です。PHP は内部で zval を使用して、任意のタイプの値を保存します。zval の構造は次のとおりです (例として 5.2):
struct _zval_struct { /* Variable information */ zvalue_value value; /* value */ zend_uint refcount; zend_uchar type; /* active type */ zend_uchar is_ref; };
上記の構造では、実際の値自体は zvalue_value 共用体です。:
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;
Today'sこのトピックでは、lval と dval の 2 つのメンバーのみに焦点を当てます。long lval は、コンパイラと OS の語長に応じて不定の長さになることを認識する必要があります。32 ビットまたは 64 ビットの可能性があり、double dval (倍精度) があります。 IEEE 754 で規定されています。固定長であり、64 ビットである必要があります。
これを覚えておいてください。これにより、一部の PHP コードは「プラットフォームに依存しない」「プロパティ」になります。特に指定がない限り、以下の説明は次のことを前提としています。 long は 64 ビット
# IEEE 754 浮動小数点のカウント方法です。ここでは引用しません。興味のある方はご自身で調べてください。ポイントの 1 つは、double の仮数部が格納されることです。 52 ビットです。隠れた 1 つの有効ビットを数えると、合計は 53 ビットです。
ここで、興味深い質問が生じます。例として C コードを使用してみましょう (long が 64 ビットであると仮定します):
long a = x; assert(a == (long)(double)a);
すみません、a の値がどの範囲内にある場合、上記のコードは成功すると断言できますか? (答えは記事の最後に残しておきます)
ここでトピック「PHP Before」に戻ります。スクリプトを実行するには、まずスクリプトを読み取って分析する必要があります。このプロセスには、スクリプト内のリテラルの zval 化も含まれます。たとえば、次のスクリプトの場合:
<?php $a = 9223372036854775807; //64位有符号数最大值 $b = 9223372036854775808; //最大值+1 var_dump($a); var_dump($b);
出力:
int(9223372036854775807) float(9.22337203685E+18)
つまり、字句解析フェーズ中に、PHP はリテラル値が現在のシステムの長いテーブル値の範囲を超えているかどうかを判断します。超えていない場合は、lval を使用して保存し、zval は IS_LONG になります。それ以外の場合は、 lval を使用して保存します。dval を使用して表現してください (zval IS_FLOAT)。
精度が失われる可能性があるため、最大の整数値より大きい値には注意する必要があります:
<?php $a = 9223372036854775807; $b = 9223372036854775808; var_dump($a === ($b - 1));
出力は false です。
ここで最初の議論を続けますが、前述したように、PHP の整数は 32 ビットまたは 64 ビットであるため、一部のコードは 64 ビットで正常に実行できると判断されています。 -bit は、目に見えない型変換により精度が失われ、コードが 32 ビット システム上で適切に実行されなくなるため、失敗する可能性があります。
したがって、この重要な値には注意する必要があります。幸いなことに、この重要な値はすでに公開されています。 PHP での定義:
<?php echo PHP_INT_MAX; ?>
もちろん、安全のために、文字列を使用して大きな整数を保存し、bcmath などの数学関数ライブラリを使用して計算を実行する必要があります。
さらに、 「私たちは混乱しています。この構成は php.precision です。この構成は、浮動小数点数を出力するときに PHP が出力する有効ビット数を決定します。
最後に、上で挙げた質問を振り返ってみましょう。これは Long です。float に変換してから long に戻すときに精度が失われないようにするための整数の最大値は何ですか?
たとえば、整数の場合、そのバイナリは次のようになります。表現は 101 です。次に、2 ビット右にシフトして 1.01 にし、上位ビットの暗黙的な有効ビット 1 を破棄して、double に格納されたバイナリ値 5 を取得します。
0/*符号位*/ 10000000001/*指数位*/ 0100000000000000000000000000000000000000000000000000
この場合、仮数部に保存される 5 のバイナリ表現は、精度を失うことなく double から long に変換されます。
double は仮数を表すために 52 ビットを使用することがわかっています。最初の 1 の場合、精度は合計 53 ビットです。次に、long 整数の値が
2^53 - 1 == 9007199254740991; //牢记, 我们现在假设是64bits的long
より小さい場合、この整数は、long-> の場合でも精度を失うことはないと結論付けることができます。 ;double->long 値変換が発生します。
推奨: "PHP チュートリアル "
以上がPHP 浮動小数点数について知っておくべきことの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。