2017-07-21 1 views
3

PHPのバージョンにNANを手渡しNANNAN振る舞いに等しい変数を異なるPHPのバージョンによっては、なぜ誰も説明できますか?は正しく

PHP Version: 5.3.5 
0 < NAN ? TRUE 
0 > NAN ? TRUE 
0 == NAN ? FALSE 
0 < $nan ? TRUE 
0 > $nan ? TRUE 
0 == $nan ? FALSE 
is_nan(NAN) TRUE 
is_nan($nan) TRUE 
gettype(NAN) is double 
gettype($nan) is double 

PHP Version: 5.6.30 (and 5.5.30, 5.4.45) 
0 < NAN ? FALSE 
0 > NAN ? FALSE 
0 == NAN ? FALSE 
0 < $nan ? FALSE 
0 > $nan ? FALSE 
0 == $nan ? FALSE 
is_nan(NAN) TRUE 
is_nan($nan) TRUE 
gettype(NAN) is double 
gettype($nan) is double 

PHP Version: 7.1.1 (and 7.0.15) 
0 < NAN ? TRUE 
0 > NAN ? TRUE 
0 == NAN ? FALSE 
0 < $nan ? FALSE 
0 > $nan ? FALSE 
0 == $nan ? FALSE 
is_nan(NAN) TRUE 
is_nan($nan) TRUE 
gettype(NAN) is double 
gettype($nan) is double 

は、PHPでの関数が依存することができます:私はPHP(使用MAMP)の多くのバージョンされている次のような結果に対してこのコードを実行した場合、今

$nan = NAN; 
print "PHP Version: " . phpversion(). "\n" . 
    '0 < NAN ? ' . (0 < NAN ? 'TRUE' : 'FALSE') . "\n" . 
    '0 > NAN ? ' . (0 > NAN ? 'TRUE' : 'FALSE') . "\n" . 
    '0 == NAN ? ' . (0 == NAN ? 'TRUE' : 'FALSE') . "\n" . 
    '0 < $nan ? ' . (0 < $nan ? 'TRUE' : 'FALSE') . "\n" . 
    '0 > $nan ? ' . (0 > $nan ? 'TRUE' : 'FALSE') . "\n" . 
    '0 == $nan ? ' . (0 == $nan ? 'TRUE' : 'FALSE') . "\n" . 
    'is_nan(NAN) ' . (is_nan(NAN) ? 'TRUE' : 'FALSE') . "\n" . 
    'is_nan($nan) ' . (is_nan($nan) ? 'TRUE' : 'FALSE') . "\n" . 
    'gettype(NAN) is ' . gettype(NAN) . "\n" . 
    'gettype($nan) is ' . gettype($nan) . "\n"; 

は、次のコードを考えてみましょうNANとの比較でNANをis_nan()とだけ使用する必要がありますか?

答えて

3

このバグはthis commitで修正されました。以下の説明は、その原因を示しています。

PHP7以降、コンパイル中か実行時に式が評価されるかによって、結果が異なるようです。

まず、IEEE754によれば、いずれかの要素がNANであるすべての比較は、falseを返す必要があることに注意することが重要です。詳細はthis answerにあります。これを考慮すると、5.6の動作は正しいと思われる。

だから

は、実行時の評価(0 < $nan)の場合について、その比較はthis codeによってVMで行われる:

result = ((double)Z_LVAL_P(op1) < Z_DVAL_P(op2)); 

操作が最終的に返されるresultに0を代入すること。これにより、期待される出力はFALSEになります。コンパイル時の評価(0 < NAN)、IRはthis codeによってコンパイル時に行われ、比較の場合


case TYPE_PAIR(IS_LONG, IS_DOUBLE): 
    Z_DVAL_P(result) = (double)Z_LVAL_P(op1) - Z_DVAL_P(op2); 
    ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result))); 
    return SUCCESS; 

ここで起こっていくつかの他のものは、減算0 - NAN = NANその値の結果は、ありますSすることができますように

#define ZEND_NORMALIZE_BOOL(n)   \ 
    ((n) ? (((n)>0) ? 1 : -1) : 0) 

:その後、次のように読み込むZEND_NORMALIZE_BOOLマクロを通過(n) > 0が(NANためのケースである)falseであれば、EE、マクロは-1を返します。 その値は、is_smaller_functionyou'll findに渡されます。

ZVAL_BOOL(result, (Z_LVAL_P(result) < 0)); 

この時点でresult-1を保持していることを考えると、これはTRUEに評価されます。あなたの2番目の質問について


、私はあなたがNANとの比較に依存していないとis_nan()を使用してに固執するん示唆しています。なお、NAN == NANfalseと評価されます。

+0

感謝。 7+ではコンパイルベースの評価でTRUEの結果が得られるのは奇妙なことです。私のために家を取ることは、NANの比較の可能性を避けることです... – Andy

+0

それは実際に把握するのが楽しいでした。 :) FYI、バグが報告されました:https://bugs.php.net/bug.php?id=74974 – pmmaga

1

これはdocumentationNaNについてこう言われる、いくつかの数値演算が一定NANによって表される値になることが

NaNの。この結果は、浮動小数点計算では未定義または表現できない値を表します。 TRUEを除き、他の値とのこの値の緩やかな比較や厳密な比較の結果はFALSEになります。

NANは任意の数の異なる値を表しますので、NANはそれ自身を含む他の値と比較されるべきではなく、代わりにis_nan()を使用することを確認する必要があります。

普通の英語では、NaNは値ではありません。これは、浮動小数点標準を使用する実数の内部表現を使用して計算または格納することができない結果を示す表記法です。

NaNは他にはありません。 NaNは、多くの異なる計算がNaNを生成する可能性があるため、別のNaNと同じでもありません。

結果がNaNかどうかを確認する唯一の信頼できる方法は、is_nan()関数を使用することです。

は、あなたのコードから最後の4つのテストが有効です。探偵の仕事のため

is_nan(NAN) TRUE 
is_nan($nan) TRUE 
gettype(NAN) is double 
gettype($nan) is double