Frage

Ok, PHP ist also nicht die beste Sprache für den Umgang mit beliebig großen Ganzzahlen, wenn man bedenkt, dass es nativ nur 32-Bit-Ganzzahlen mit Vorzeichen unterstützt.Was ich jedoch versuche, ist, eine Klasse zu erstellen, die eine beliebig große Binärzahl darstellen und in der Lage sein könnte, einfache arithmetische Operationen an zwei davon durchzuführen (addieren/subtrahieren/multiplizieren/dividieren).

Mein Ziel ist der Umgang mit 128-Bit-Ganzzahlen.

Es gibt ein paar Ansätze, die ich mir anschaue, und bei denen ich Probleme sehe.Für jede Eingabe oder jeden Kommentar dazu, was Sie wählen würden und wie Sie dabei vorgehen könnten, wären wir sehr dankbar.

Ansatz Nr. 1: Erstellen Sie eine 128-Bit-Ganzzahlklasse, die ihre Ganzzahl intern als vier 32-Bit-Ganzzahlen speichert.Das einzige Problem bei diesem Ansatz besteht darin, dass ich nicht sicher bin, wie ich mit Überlauf-/Unterlaufproblemen umgehen soll, wenn ich einzelne Teile der beiden Operanden manipuliere.

Ansatz Nr. 2: Verwenden Sie die bcmath-Erweiterung, da diese scheinbar etwas ist, für das sie entwickelt wurde.Meine einzige Sorge bei diesem Ansatz ist die Skalierungseinstellung der bcmath-Erweiterung, da in meinen 128-Bit-Ganzzahlen keine Rundungsfehler auftreten dürfen.sie müssen präzise sein.Ich mache mir auch Sorgen, ob ich das Ergebnis der bcmath-Funktionen irgendwann in eine Binärzeichenfolge umwandeln kann (die ich später in einige mcrypt-Verschlüsselungsfunktionen einfügen muss).

Ansatz Nr. 3: Speichern Sie die Zahlen als Binärzeichenfolgen (wahrscheinlich zuerst LSB).Theoretisch sollte ich auf diese Weise in der Lage sein, ganze Zahlen beliebiger Größe zu speichern.Alles, was ich tun müsste, ist, die vier grundlegenden arithmetischen Funktionen zu schreiben, um Add/Sub/Mult/Div für zwei Binärzeichenfolgen auszuführen und ein Binärzeichenfolgenergebnis zu erzeugen.Das ist genau das Format, das ich auch an mcrypt übergeben muss, das ist also ein zusätzlicher Pluspunkt.Dieser Ansatz ist meiner Meinung nach im Moment der vielversprechendste, aber der einzige Knackpunkt, den ich habe, ist, dass PHP mir keine Möglichkeit bietet, die einzelnen Bits zu manipulieren (von denen ich weiß).Ich glaube, ich müsste es in bytegroße Blöcke aufteilen (kein Wortspiel beabsichtigt). An diesem Punkt gelten meine Fragen zum Umgang mit Überlauf/Unterlauf aus Ansatz Nr. 1.

War es hilfreich?

Lösung

Der PHP-GMP-Erweiterung wird dafür besser geeignet sein.Als zusätzlichen Bonus können Sie damit Ihre Dezimal-zu-Binär-Konvertierung durchführen, etwa so:

gmp_strval(gmp_init($n, 10), 2);

Andere Tipps

Es gibt bereits verschiedene Klassen verfügbar Daher möchten Sie sie möglicherweise vor dem Schreiben Ihrer eigenen Lösung durchsehen (falls Sie tatsächlich noch eine eigene Lösung schreiben müssen).

Soweit ich das beurteilen kann, ist die bcmath-Erweiterung die richtige für Sie.Die Daten im PHP-Handbuch sind etwas spärlich, aber Sie können die Genauigkeit mithilfe der Funktion bcscale() oder des optionalen dritten Parameters in den meisten anderen bcmath-Funktionen genau so einstellen, wie Sie es benötigen.Ich bin mir bei der Sache mit den Binärzeichenfolgen nicht ganz sicher, aber ein bisschen googeln sagt mir, dass Sie mit der Funktion pack() zurechtkommen sollten.

Folgendes habe ich umgesetzt BC-Bewerter für PEMDAS-Beschwerden was für Sie nützlich sein könnte.

function BC($string, $precision = 32)
{
    if (extension_loaded('bcmath') === true)
    {
        if (is_array($string) === true)
        {
            if ((count($string = array_slice($string, 1)) == 3) && (bcscale($precision) === true))
            {
                $callback = array('^' => 'pow', '*' => 'mul', '/' => 'div', '%' => 'mod', '+' => 'add', '-' => 'sub');

                if (array_key_exists($operator = current(array_splice($string, 1, 1)), $callback) === true)
                {
                    $x = 1;
                    $result = @call_user_func_array('bc' . $callback[$operator], $string);

                    if ((strcmp('^', $operator) === 0) && (($i = fmod(array_pop($string), 1)) > 0))
                    {
                        $y = BC(sprintf('((%1$s * %2$s ^ (1 - %3$s)) / %3$s) - (%2$s / %3$s) + %2$s', $string = array_shift($string), $x, $i = pow($i, -1)));

                        do
                        {
                            $x = $y;
                            $y = BC(sprintf('((%1$s * %2$s ^ (1 - %3$s)) / %3$s) - (%2$s / %3$s) + %2$s', $string, $x, $i));
                        }

                        while (BC(sprintf('%s > %s', $x, $y)));
                    }

                    if (strpos($result = bcmul($x, $result), '.') !== false)
                    {
                        $result = rtrim(rtrim($result, '0'), '.');

                        if (preg_match(sprintf('~[.][9]{%u}$~', $precision), $result) > 0)
                        {
                            $result = bcadd($result, (strncmp('-', $result, 1) === 0) ? -1 : 1, 0);
                        }

                        else if (preg_match(sprintf('~[.][0]{%u}[1]$~', $precision - 1), $result) > 0)
                        {
                            $result = bcmul($result, 1, 0);
                        }
                    }

                    return $result;
                }

                return intval(version_compare(call_user_func_array('bccomp', $string), 0, $operator));
            }

            $string = array_shift($string);
        }

        $string = str_replace(' ', '', str_ireplace('e', ' * 10 ^ ', $string));

        while (preg_match('~[(]([^()]++)[)]~', $string) > 0)
        {
            $string = preg_replace_callback('~[(]([^()]++)[)]~', __FUNCTION__, $string);
        }

        foreach (array('\^', '[\*/%]', '[\+-]', '[<>]=?|={1,2}') as $operator)
        {
            while (preg_match(sprintf('~(?<![0-9])(%1$s)(%2$s)(%1$s)~', '[+-]?(?:[0-9]++(?:[.][0-9]*+)?|[.][0-9]++)', $operator), $string) > 0)
            {
                $string = preg_replace_callback(sprintf('~(?<![0-9])(%1$s)(%2$s)(%1$s)~', '[+-]?(?:[0-9]++(?:[.][0-9]*+)?|[.][0-9]++)', $operator), __FUNCTION__, $string, 1);
            }
        }
    }

    return (preg_match('~^[+-]?[0-9]++(?:[.][0-9]++)?$~', $string) > 0) ? $string : false;
}

Rundungsfehler werden automatisch berücksichtigt. Stellen Sie einfach die Genauigkeit auf die benötigten Ziffern ein.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top