8

いくつかの整数演算は、歴史的な理由から、静的に型付けされたいくつかの言語と同じように PHP でも動作する必要があります。最後に PHP をアップグレードしてから、整数のオーバーフローに対する動作が変更されました。基本的には次の式を使用しています。

function f($x1, $x2, $x3, $x4)
{
   return (($x1 + $x2) ^ $x3) + $x4;
}

ただし、変換があっても:

function f($x1, $x2, $x3, $x4)
{
   return intval(intval(intval($x1 + $x2) ^ $x3) + $x4);
}

私はまだ完全に間違った番号になってしまいます...

たとえば、$x1 = -1580033017、$x2 = -2072974554、$x3 = -1170476976) および $x4 = -1007518822 では、PHP では -30512150、C# では 1617621783 になります。

$x1 と $x2 を加算するだけでは、正しい答えが得られません。

C#で私は得る

(-1580033017 + -2072974554) = 641959725

PHP の場合:

intval(intval(-1580033017) + intval(-2072974554)) = -2147483648

これは次と同じです:

intval(-1580033017 + -2072974554) = -2147483648

「IntegerOverflowAdd」関数などを書いても構いませんが、(-1580033017 + -2072974554) がどのように 641959725 に等しいかはよくわかりません (-2147483648 + (2 * 2^31) であることは認識しています)。 、しかし -2147483648 + 2^31 は -1505523923 であり、Int.Min よりも大きいので、なぜ 2^31 ではなく 2*2^31 を追加するのですか?)

どんな助けでも大歓迎です...

4

6 に答える 6

14

そこで私は問題を解決し、PHP について多くのことを発見しました (少なくとも、整数オーバーフローの処理方法について)。

1) マシンが実行されているプラ​​ットフォーム、PHP のバージョン、Suhosin Hardened PHP が実行されているかどうか、およびコンパイルされたビット数 (32 または 64) の間のクロスに完全に依存していました。6 台のマシンは私が期待したとおりに動作し (実際には間違っていました。少なくともドキュメントによれば間違っていました)、3 台のマシンはまだ説明できない方法で動作し、3 台​​のマシンは intval コマンドが示しているとおりに動作しました。ドキュメンテーション。

2) int > PHP_INT_MAX (int & 0xffffffff ではない) の場合、Intval は PHP_INT_MAX を返すはずですが、これは PHP4 および PHP5 の一部のバージョンでのみ発生します。int > PHP_INT_MAX の場合、PHP のバージョンが異なれば、異なる値が返されます。

3) 次のコードは、3 つの異なる結果を返す可能性があります (1 を参照)。

<?php
echo "Php max int: ".PHP_INT_MAX."\n";
echo "The Val: ".(-1580033017 + -2072974554)."\n";
echo "Intval of the val: ".intval(-3653007571)."\n";
echo "And 0xffffffff of the val: ".(-3653007571 & 0xffffffff)."\n";
?>

返すことができます (これは Intval には正しいように見えますが、& 0xffffff には間違っています)。

Php max int: 2147483647
The Val: -3653007571
Intval of the val: -2147483648
And of the val: -2147483648

そしてそれは返すことができます (これは intval の PHP ドキュメントと矛盾します):

Php max int: 2147483647
The Val: -3653007571
Intval of the val: -641959725
And of the val: -641959725

64 ビット マシンでは次のように返されます (これは正しいです)。

Php max int: 2147483647
The Val: -3653007571
Intval of the val: -3653007571
And of the val: -641959725

解決

とにかく、これらすべてのプラットフォームで動作し、特定の Max int でコンパイルされた特定のバージョンの PHP の癖に依存しないソリューションが必要でした。したがって、私は次のクロス PHP 30TwoBitIntval 関数を考え出しました。

function thirtyTwoBitIntval($value)
{
    if ($value < -2147483648)
    {
        return -(-($value) & 0xffffffff);
    }
    elseif ($value > 2147483647)
    {
        return ($value & 0xffffffff);
    }
    return $value;
}

コメント

PHP の設計者は、Int が 32 ビット、64 ビット、または 128 ビットのマシン (たとえば DotNet CLR など) で実行されているかどうかに関係なく、32 ビットの Int であると言うべきだったと思います。 PHP がコンパイラーの下にあるビットの数に応じて浮動小数点数。

于 2008-11-19T23:53:17.977 に答える
11

32 ビット プラットフォームと 64 ビット プラットフォームの両方で 32 ビットの intval に対して 100% 機能するソリューションが必要な場合は、次のソリューションを使用することをお勧めします。

function intval32bits($value)
{
    $value = ($value & 0xFFFFFFFF);

    if ($value & 0x80000000)
        $value = -((~$value & 0xFFFFFFFF) + 1);

    return $value;
}
于 2010-01-23T14:27:36.293 に答える
3

内部的には、PHPはほとんどの数値に「整数」型を使用します。ただし、これらはこれまでのところのみです。大きな整数を大きな整数に追加すると、PHPは結果が大きすぎて通常の整数に収まらないことを認識し、浮動小数点数に割り当てます。ただし、浮動小数点数(floats)自体は非常に高くなるだけであり、16桁のマークの周りにPHPがプロットを完全に失うポイントがあります。

文字列として表される、任意のサイズと精度の数値をサポートする任意精度の数学を使用するオプションがあります。詳細はこちら: http: //us2.php.net/bc

于 2008-11-19T02:39:54.943 に答える
2

PHPの整数がC#のように符号なし32ビットであることに関係しているのではないかと思います。デフォルトでは、符号付き32ビットです。

通常の31〜32ビット範囲の端にある数値で遊んでいます。

PHPマニュアルの追加のドキュメントを参照してください。

http://www.php.net/manual/en/language.types.integer.php

整数のサイズはプラットフォームに依存しますが、最大値の約20億が通常の値(32ビット符号付き)です。PHPは符号なし整数をサポートしていません。整数サイズは定数PHP_INT_SIZEを使用して決定でき、最大値は定数PHP_INT_MAXを使用してPHP4.4.0およびPHP5.0.5以降で決定できます。

于 2008-11-19T02:34:30.150 に答える
2

これは機能しますか?

echo (-1580033017 + -2072974554) & 0xffffffff

一般化すると、次のことができます(構文エラーはご容赦ください。私は、長い間PHPに触れていません)。

function s32add($a, $b) {
    return ($a + $b) & 0xffffffff;
}
于 2008-11-19T02:36:43.733 に答える
1

PHP のバージョン番号を確認してください。長い整数のサポートが異なる PHP のバージョンが異なると、異なる結果が得られる可能性があると思います。PHP 5 バージョンの最後の 1 つに、長い整数に関するバグがあったと思います。

バージョンPHP 5.2.0では、答えはC#で得たものとまったく同じです

1617621783、

上記の正確な機能を利用します。

phpinfo()コマンドを使用して、バージョン番号を簡単に見つけることができます。

$x1 = -1580033017; 
$x2 = -2072974554; 
$x3 = -1170476976 ; 
$x4 = -1007518822;
echo f($x1, $x2, $x3, $x4);

function f($x1, $x2, $x3, $x4)
{
   return intval(intval(intval($x1 + $x2) ^ $x3) + $x4);
}
于 2008-11-19T03:22:15.280 に答える