Galileo Computing < openbook >
Galileo Computing - Programming the Net
Galileo Computing - Programming the Net


Java ist auch eine Insel (2. Aufl.) von Christian Ullenboom
Programmieren für die Java 2-Plattform in der Version 1.4
Java ist auch eine Insel (2. Auflage)
gp Kapitel 5 Mathematisches
  gp 5.1 Arithmetik in Java
  gp 5.2 Die Funktionen der Math-Klasse
    gp 5.2.1 Attribute
    gp 5.2.2 Winkelfunktionen (trigonometrische Funktionen und Arcus–Funktionen)
    gp 5.2.3 Runden von Werten
    gp 5.2.4 Exponentialfunktionen
    gp 5.2.5 Division
    gp 5.2.6 Absolutwerte und Maximum, Minimum
    gp 5.2.7 Zufallszahlen
  gp 5.3 Mathe bitte strikt
    gp 5.3.1 Strikt Fließkomma mit strictfp
    gp 5.3.2 Die Klassen Math und StrictMath
  gp 5.4 Die Random-Klasse
  gp 5.5 Große Zahlen
    gp 5.5.1 Die Klasse BigInteger
    gp 5.5.2 Ganz lange Fakultäten
  gp 5.6 Probleme mit Java und der Mathematik
  gp 5.7 Das Java-Matrix-Paket Jama


Galileo Computing

5.5 Große Zahlen  downtop

Die feste Länge der primitiven Datentypen int, long für Ganzzahlwerte und float, double für Fließkommawerte reichen für diverse numerische Berechnungen nicht aus. Besonders wünschenswert sind größere Zahlen in der Kryptographie. Für solche Anwendungen gibt es im math-Paket zwei Klassen: BigInteger für Ganzzahlen und BigDecimal für Gleitkommazahlen.


Galileo Computing

5.5.1 Die Klasse BigInteger  downtop

Mit der Klasse BigInteger ist es uns möglich, beliebig genaue Zahlen anzulegen, zu verwalten und damit zu rechnen. Die BigInteger-Objekte werden dabei immer so lang, wie die entsprechenden Ergebnisse Platz benötigen (engl. »infinite word size«). Die Berechnungsmöglichkeiten gehen dabei weit über die der primitiven Typen hinaus und bieten des Weiteren viele der statischen Methoden der Math-Klasse. Zu den Erweiterungen gehören modulare Arithmetik, Bestimmung des größten gemeinsamen Teilers (ggT), Pseudo-Primzahltests, Bitmanipulation und weiteres.

Ein BigInteger-Objekt wird dabei intern wie der primitive Datentyp im Zweierkomplement dargestellt. Auch die weiteren Operationen entsprechen den Ganzzahl-Operationen der primitiven Datentypen, wie etwa die Division durch Null. Sie löst eine ArithmeticException aus. Da ein Überlauf nicht möglich ist, weil intern der Speicher angepasst wird, muss ein Anwender gegebenenfalls einen eigenen Überlauftest in sein Programm einbauen, wenn er den Wertebereich beschränken will. Da die Größe des Datentyps bei Bedarf immer ausgedehnt wird, sind einige Operationen ebenfalls nicht übertragbar. So kann der Verschiebe-Operator >>> nicht übernommen werden, denn bei einer Rechtsverschiebung haben wir kein Vorzeichen-Bit im BigInteger. Auch bei logischen Operatoren muss eine Interpretation der Werte vorgenommen werden. Bei Operationen auf zwei BigInteger-Objekten mit unterschiedlicher Bitlänge wird der kleinere dem größeren durch Replikation (Wiederholung) des Vorzeichen-Bits angepasst. Über spezielle Bitoperatoren können einzelne Bits gesetzt werden. Wie bei der Klasse BitSet lassen sich durch die »unendliche« Größe Bits setzen, auch wenn die Zahl nicht so viele Bits benötigt. Durch die Bitoperationen lässt sich das Vorzeichen einer Zahl nicht verändern; gegebenenfalls wird vor der Zahl ein neues Vorzeichen-Bit mit dem ursprünglichen Wert ergänzt.

BigInteger-Objekte erzeugen

Zur Erzeugung stehen uns verschiedene Konstruktoren zur Verfügung. Einen Standard-Konstruktor gibt es nicht. Neben Konstruktoren, die das Objekt mit Werten aus einem Bytefeld oder String initialisieren, lässt sich auch ein Objekt mit einer zufälligen Belegung erzeugen. Die Klasse BigInteger bedient sich dabei der Klasse java.util.Random. Ebenso lassen sich BigInteger-Objekte erzeugen, die Pseudo-Primzahlen sind. Bei den Konstruktoren mit String-Parametern wird im Fehlerfall eine NumberFormatException ausgeworfen.

class java.math.BigInteger
extends Number

gp  BigInteger( byte val[] )
Ein Bytefeld mit einer Zweierkomplement-Repräsentation einer BigInteger-Zahl im Big-Endian-(Array-Element mit Index 0, enthält die niederwertigsten Bits) Format initialisiert das neue BigInteger-Objekt.
gp  BigInteger( int signum, byte magnitude[] )
Erzeugt aus einer Big-Endian-Betrag- beziehungsweise Vorzeichen-Repräsentation ein BigInteger-Objekt. signum gibt das Vorzeichen an und kann mit -1 (neg. Zahlen), 0 (Null) und 1 (pos. Zahlen) belegt werden.
gp  BigInteger( int bitLength, int certainty, Random rnd )
Erzeugt eine BigInteger-Zahl mit der Bitlänge bitLength (>1), bei der es sich mit gewisser Wahrscheinlichkeit um eine Primzahl handelt. Der Wert certainty bestimmt, wie wahrscheinlich ein Fehlurteil ist. Mit der Wahrscheinlichkeit 1/(2^certainty) handelt es sich bei der erzeugten Zahl fälschlicherweise doch nicht um eine Primzahl. Intern wird die private Funktion isProbablePrime()benutzt, um festzustellen, ob es sich um eine Primzahl handelt. Je größer certainty ist (je unwahrscheinlicher ein Fehlurteil ist), desto länger braucht die Funktion.
gp  BigInteger( int numbits, Random rnd )
Liefert eine Zufallszahl aus dem Wertebereich 0 bis 2^numBits – 1. Alle Werte sind gleich wahrscheinlich.
gp  BigInteger( String val )
Erzeugt ein BigInteger aus einem Ziffern-String mit einem optionalen Vorzeichen.
gp  BigInteger( String val, int radix )
Ein String mit einem optionalen Vorzeichen wird zu einem BigInteger-Objekt übersetzt. Dabei wird die angegebene Basis radix verwendet, um die Zeichen des Strings als Ziffern zu interpretieren. Für radix > 10 werden die Buchstaben A-Z beziehungsweise a–z als zusätzliche »Ziffern« verwendet.
Beispiel   Gegeben sei eine Zeichenkette, die eine Binärfolge aus Nullen und Einsen kodiert. Dann lässt sich ein Objekt der Klasse BigInteger nutzen, um diese Zeichenkette in ein Byte-Array zu konvertieren:
String s = "1101110110101010001010100010101";
byte b[] = new BigInteger(s, 2).toByteArray();
for ( int i = 0; i < b.length; i++ )
  System.out.println( Integer.toBinaryString(b[i]&0xff) );

Leider gibt es immer noch keinen Konstruktor, der auch long-Datentypen annimmt. Das ist seltsam, denn es gibt die statische Methode valueOf(), die BigInteger-Objekte erzeugt. Dies ist sehr verwirrend, denn viele Programmierer übersehen diese Funktion und gehen über ein String-Objekt. Besonders ärgerlich ist es dann zu sehen, dass es einen privaten Konstruktor gibt, der mit einem long arbeitet. Genau diesen Konstruktor nutzt dann auch valueOf().

Im Endeffekt sind also die folgenden Zeilen gleichwertig:

BigInteger bi = BigInteger.valueOf( 123456789 );       // (1)
BigInteger bi = new BigInteger( ""+123456789 );        // (2)

Neben den Konstruktoren und dem valueOf() gibt es zwei Konstanten für die Werte 0 und 1.

gp  static final BigInteger ZERO
Der Wert berechnet sich aus der Anweisung new BigInteger(new byte[0], 0).
gp  static final BigInteger ONE
Der Wert wird mit valueOf(1) berechnet.

Obwohl es intern noch eine Konstante TWO gibt, ist diese privat, von außen besteht also keine Möglichkeit, auf sie zuzugreifen.


Galileo Computing

5.5.2 Ganz lange Fakultäten  toptop

Unser Beispielprogramm soll nun die Fakultät einer natürlichen Zahl berechnen. Die Zahl muss positiv sein.

Listing 5.4   Fakultaet.java

import java.math.*;

class Fakultaet
{
  static BigInteger fakultät( int n )
  {
    BigInteger big = BigInteger.ONE;

    if ( n == 0 || n == 1 )
      return big;

    if ( n > 1 )
      for ( int i = 1; i <= n; i++ )
        big = big.multiply( BigInteger.valueOf(i) );

    return big;
  }

  static public void main( String args[] )
  {
    System.out.println( fakultät(100) );
  }
}

Neben dieser iterativen Variante ist auch noch eine rekursive denkbar. Sie ist allerdings aus zwei Gründen nicht wirklich gut. Zuerst aufgrund des hohen Speicherplatzbedarfs. Für die Berechnung von n! müssen n Objekte erzeugt werden. Im Gegensatz zur iterativen Funktion müssen diese jedoch alle im Speicher gehalten werden, bis die Rekursion aufgelöst wird. Dadurch ergibt sich die zweite Schwäche, die längere Laufzeit. Aus akademischen Gründen soll die Methode hier allerdings aufgeführt werden. Es wäre interessant, einmal zu beobachten, wie der Speicher bei dieser Implementierung aufgezehrt wird.

public static BigInteger fakultät_rek( int i )
{
  if ( i <= 1 )
    return BigInteger.ONE;
  else
  {
    BigInteger bi = BigInteger.valueOf(i);
    return bi.multiply( fakultät_rek( i-1 ) );
  }
}





1   Einige Systeme produzieren ab fakultaet_rek (7750) einen java.lang.StackOverflowError, andere erst ab 43200.





Copyright © Galileo Press GmbH 2003
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press GmbH, Gartenstraße 24, 53229 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de