c# - real - Force PHP-Ganzzahlüberlauf




signed integer overflow (4)

Wir haben eine Integer-Arithmetik, die aus historischen Gründen auf PHP genauso funktioniert wie auf einigen statisch typisierten Sprachen. Seit der letzten Aktualisierung von PHP hat sich das Verhalten für überlaufende ganze Zahlen geändert. Grundsätzlich verwenden wir folgende Formel:

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

Allerdings auch bei Conversions:

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

Ich habe immer noch die völlig falsche Nummer ...

Zum Beispiel, mit $ x1 = -1580033017, $ x2 = -2072974554, $ x3 = -1170476976) und $ x4 = -1007518822, endete ich mit -30512150 in PHP und 1617621783 in C #.

Wenn ich nur $ x1 und $ x2 addiere, bekomme ich nicht die richtige Antwort:

In C # bekomme ich

(-1580033017 + -2072974554) = 641959725

In PHP:

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

das ist das gleiche wie:

intval(-1580033017 + -2072974554) = -2147483648

Ich habe nichts dagegen, eine "IntegerOverflowAdd" -Funktion oder etwas zu schreiben, aber ich kann nicht ganz herausfinden, wie (-1580033017 + -2072974554) 641959725 entspricht. (Ich erkenne, dass es -2147483648 + (2 * 2 ^ 31) ist , aber -2147483648 + 2 ^ 31 ist -1505523923, was größer ist als Int.Min. Warum addieren Sie 2 * 2 ^ 31 und nicht 2 ^ 31?

Jede Hilfe wäre willkommen ...


Überprüfen Sie Ihre Versionsnummer von PHP - ich glaube, es ist möglich, dass Sie unterschiedliche Ergebnisse mit verschiedenen Versionen von PHP erhalten, die unterschiedliche Unterstützung für lange ganze Zahlen haben können. Ich glaube, es gab einen Fehler mit langen ganzen Zahlen in der letzten Version von PHP 5.

In der Version PHP 5.2.0 ist die Antwort GENAU dasselbe wie in C #

1617621783,

die genaue Funktion verwenden, die Sie oben haben.

Mit dem Befehl phpinfo () können Sie leicht Ihre Versionsnummer finden.

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

Ich denke, es kann damit zu tun haben, dass die ganze Zahl in PHP 32 Bit ohne Vorzeichen ist, da in C # standardmäßig 32 Bit vorangestellt sind.

Sie spielen mit Zahlen am Rande des normalen 31-32 Bit-Bereichs.

Bitte beachten Sie die zusätzliche Dokumentation im PHP-Handbuch:

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

Die Größe einer ganzen Zahl ist plattformabhängig, obwohl ein Maximalwert von ungefähr zwei Milliarden der übliche Wert ist (das ist 32 Bit signiert). PHP unterstützt keine unsignierten ganzen Zahlen. Die Integer-Größe kann mit der Konstanten PHP_INT_SIZE und der Maximalwert mit der Konstanten PHP_INT_MAX seit PHP 4.4.0 und PHP 5.0.5 ermittelt werden.


Ob das funktioniert?

echo (-1580033017 + -2072974554) & 0xffffffff

Um zu verallgemeinern, könnten Sie tun (verzeihen Sie alle Syntaxfehler, ich habe PHP lange Zeit nicht berührt):

function s32add($a, $b) {
    return ($a + $b) & 0xffffffff;
}

So löste ich das Problem und entdeckte eine Menge über PHP (zumindest in der Art, wie es Integer-Überläufe handhabt).

1) Es hing völlig von einer Kreuzung ab, auf welcher Plattform die Maschine lief, welche Version von PHP, ob Suhosin Hardened PHP lief und wie viele Bits es kompiliert wurde (32 oder 64). 6 Maschinen verhielten sich so, wie ich es erwartet hatte (was eigentlich falsch war, zumindest laut Dokumentation) und 3 Maschinen verhielten sich so, wie ich es immer noch nicht erklären kann, und 3 Maschinen verhielten sich entsprechend dem Befehl intval. Dokumentation.

2) Intval soll PHP_MAX_INT zurückgeben, wenn int> PHP_MAX_INT (nicht int & 0xffffffff), aber dies geschieht nur auf einigen Versionen von PHP4 und PHP5. Verschiedene Versionen von PHP geben unterschiedliche Werte zurück, wenn int> PHP_MAX_INT ist.

3) Der folgende Code kann 3 verschiedene Ergebnisse zurückgeben (siehe 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";
?>

Es kann zurückkehren (was für Intval aber für & 0xffffff falsch ist)

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

Und es kann zurückkehren (was der PHP-Dokumentation für intval widerspricht):

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

Und auf 64 Bit Rechnern gibt es zurück (was richtig ist):

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

Lösung

Irgendwie brauchte ich eine Lösung, die auf all diesen Plattformen funktionieren würde und nicht abhängig von Macken einer bestimmten Version von PHP wäre, die mit einem bestimmten Max int kompiliert wurde. Also habe ich mit der folgenden cross-PHP threeTwoBitIntval Funktion aufgetaucht:

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

Kommentar

Ich denke, die Entwickler von PHP sollten gesagt haben, dass ein Int ein 32-Bit-Int ist, egal ob er auf einem 32- oder 64- oder 128-Bit-Rechner läuft (wie zum Beispiel DotNet CLR) und ihn nicht nach dem Zufallsprinzip zu einem float abhängig von der Anzahl der Bits, unter denen PHP Compiler ist.





integer-overflow