Rechnen mit beliebiger Genauigkeit

Martin Kompf

Die Genauigkeit der in die Programmierspache C eingebauten Arithmetik ist begrenzt. Erst mit der GNU Multiple Precision Arithmetic Library wird das Rechnen mit beliebig langen Zahlen möglich.

Der Computer erlaubt uns, mathematische und technische Berechnungen schneller und präziser als mit jedem anderen Hilfsmittel vorzunehmen. Er ist dabei jedoch nicht unfehlbar. Wenn sich der Anwender blind auf seinen Rechner verläßt, sind sogar falsche Resultate vorprogrammiert. Man probiere nur einmal folgenden C-Code aus:

        double d, e, f;

        d = 1000000000000000000000000.0;
        e = d + 1.0;
        f = e - d;
        printf( "the difference of %f and %f is %f\n", e, d, f);

Es wird mitnichten die Differenz 1 ausgeben, sondern 0! Was läuft hier falsch?

Die meisten Programmiersprachen - wie auch C - besitzen eine Reihe von eingebauten Datentypen für mathematische Berechnungen. Aus Performance- und Kompatibilitätsgründen sind Genauigkeit und Wertevorrat dieser eingebauten Datentypen jedoch begrenzt. So wird der im Beispiel verwendete Datentyp double intern mit 64 bit (8 byte) Länge im IEEE 754 Format (1 bit Vorzeichen, 11 bit Exponent, 52 bit Mantisse) dargestellt. Damit lassen sich zwar sehr große Zahlen (bis etwa 101000) darstellen, jedoch ist die Genauigkeit auf 15 signifikante Digits beschränkt. Die im Beispiel verwendete Zahl - eine Quadrillion (1024) - hat aber 25 Digits, deshalb scheitert die Subtraktion der im Verhältnis dazu sehr kleinen Zahl 1.

Der längste ganzzahlige Datentyp in ANSI-C ist unsigned long int mit 32 bit Länge und einem Wertebereich von 0 bis etwa 4 Milliarden (109). Der GNU Compiler hat eine Erweiterung auf den 64 bittigen Datentyp unsigned long long int, mit dem sich Zahlen bis 18 Trillionen (1018) darstellen lassen. Dies alles hilft uns aber in unserem Beispiel nicht weiter.

Die Verarbeitung solche großer Zahlen mit beliebiger Genauigkeit ist heutzutage ein wichtiges Anwendungsgebiet des Computers - insbesondere kryptografische Algorithmen erfordern dies. Deswegen gibt es auch schon eine Lösung des Problems: Die frei verfügbare GNU Multiple Precision Arithmetic Library GMP. Sie liegt natürlich im Sourcecode vor und läßt sich auf allen Unix Plattformen und Windows mit dem Cygwin Toolkit übersetzen. Unterstützung für eine Vielzahl von Prozessoren, wie DEC Alpha, AMD, Intel, Motorola, IBM PowerPC, SPARC und DEC VAX, ist vorhanden und führt zu einer sehr schnellen und effektiven Abarbeitung.

Der obige Programmausschnitt würde unter Verwendung von GMP nun so aussehen:

#include "gmp.h"

        mpz_t m, n, r;

        mpz_init( m);
        mpz_init( n);
        mpz_init( r);

        mpz_set_str( m, "1 000 000 000 000 000 000 000 000", 10);
        mpz_add_ui( n, m, 1);
        mpz_sub( r, n, m);
        printf( "the difference of %s and %s is %s (using gmp)\n",
                mpz_get_str( NULL, 10, n),
                mpz_get_str( NULL, 10, m),
                mpz_get_str( NULL, 10, r));

        mpz_clear( m);
        mpz_clear( n);
        mpz_clear( r);

Nach dem Übersetzen und Linken mit libgmp wird das richtige Ergebnis 1 zurückgeliefert. Weitere Information zum Thema können dem GMP Online-Manual entnommen werden.