Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 3. Auflage
<< | < | > | >> | API | Kapitel 17 - Utility-Klassen II

## 17.3 Die Klassen BigInteger und BigDecimal

- 17.3 Die Klassen BigInteger und BigDecimal
  - 17.3.1 Die Klasse BigInteger
  - 17.3.2 Die Klasse BigDecimal

Seit dem JDK 1.1 gibt es das Paket `java.math` mit den beiden Klassen `BigInteger` und `BigDecimal`. Beide implementieren beliebig große bzw. beliebig genaue Zahlen und stellen Methoden zur Durchführung arithmetischer Berechnungen zur Verfügung. Während `BigInteger` beliebig große Ganzzahlen implementiert, dient `BigDecimal` zur Darstellung sehr großer Fließkommazahlen. Objekte beider Klassen sind immutable, d.h. sie können nach der Instanzierung nicht mehr verändert werden.

### 17.3.1 Die Klasse BigInteger

Die einfachste Art, ein `BigInteger`-Objekt zu konstruieren, besteht darin, eine String-Repräsentation der darzustellenden Zahl an den Konstruktor zu übergeben. Das kann wahlweise mit oder ohne Angabe des Zahlensystems geschehen:

    public BigInteger(String val)

    public BigInteger(String val, int radix)
| java.math.BigInteger

Wird das Zahlensystem nicht angegeben, erwartet der Konstruktor eine Zahl zur Basis 10. Der übergebene String darf eine beliebig lange Folge von Ziffern sein. An erster Stelle kann ein Minuszeichen stehen, um eine negative Zahl anzuzeigen.

Die Arithmetik auf `BigInteger`-Zahlen erfolgt durch Aufruf ihrer arithmetischen Methoden und Übergabe der erforderlichen Argumente, die meist ebenfalls vom Typ `BigInteger` sind. Der Methodenaufruf verändert dabei nicht den Wert des Objekts, sondern gibt das Ergebnis als neue `BigInteger`-Zahl an den Aufrufer zurück. Wichtige arithmetische Methoden sind:

    public BigInteger add(BigInteger val)
    public BigInteger subtract(BigInteger val)
    public BigInteger multiply(BigInteger val)
    public BigInteger divide(BigInteger val)
    public BigInteger remainder(BigInteger val)
    public BigInteger pow(int exponent)
| java.math.BigInteger

Sie berechnen die Summe, Differenz, Produkt, Quotient, Restwert und Potenz zweier `BigInteger`-Zahlen. Neben den Grundrechenarten gibt es weitere Funktionen:

    public BigInteger abs()
    public BigInteger negate()
    public int signum()
    public BigInteger gcd(BigInteger val)

    public BigInteger min(BigInteger val)
    public BigInteger max(BigInteger val)
| java.math.BigInteger

Sie stellen den absoluten Betrag zur Verfügung, multiplizieren mit -1, liefern das Vorzeichen und ermitteln den größten gemeinsamen Teiler zweier Zahlen. `min` und `max` liefern den kleineren bzw. größeren Wert aus aktueller und als Argument übergebener Zahl. Daneben gibt es logische und bitweise Operationen, die denen der primitiven ganzzahligen Typen entsprechen.

Zum Vergleich zweier `BigInteger`-Zahlen kann `compareTo` und `equals` verwendet werden, die Konvertierung in einen String wird mit `toString` erledigt:

    public int compareTo(BigInteger val)
    public boolean equals(Object x)

    public String toString()
| java.math.BigInteger

Die Arbeitsweise dieser Methoden entspricht der in der Klasse `Object` und dem Interface `Comparable` definierten und kann in Abschnitt 8.1.2 und Abschnitt 9.2 nachgelesen werden. Schließlich gibt es noch einige Methoden, um `BigInteger`-Objekte in primitive Typen zu verwandeln:

    public int intValue()
    public long longValue()
    public float floatValue()
    public double doubleValue()
| java.math.BigInteger

Die Umwandlung folgt den in Abschnitt 4.6 beschriebenen Regeln für einschränkende Konvertierungen.

Als abschließendes Beispiel wollen wir uns ein kleines Programm ansehen, das die Fakultäten der Zahlen 30 bis 40 berechnet:

    001 /* Listing1702.java */
    002
    003 import java.math.*;
    004
    005 public class Listing1702
    006 {
    007   public static void printFaculty(int n)
    008   {
    009     BigInteger bi = new BigInteger("1");
    010     for (int i = 2; i <= n; ++i) {
    011       bi = bi.multiply(new BigInteger("" + i));
    012     }
    013     System.out.println(n + "! is " + bi.toString());
    014   }
    015
    016   public static void main(String[] args)
    017   {
    018     for (int i = 30; i <= 40; ++i) {
    019       printFaculty(i);
    020     }
    021   }
    022 }
| Listing1702.java

Listing 17.2: Anwendung der Klasse BigInteger

Die Ausgabe des Programms ist:

    30! is 265252859812191058636308480000000
    31! is 8222838654177922817725562880000000
    32! is 263130836933693530167218012160000000
    33! is 8683317618811886495518194401280000000
    34! is 295232799039604140847618609643520000000
    35! is 10333147966386144929666651337523200000000
    36! is 371993326789901217467999448150835200000000
    37! is 13763753091226345046315979581580902400000000
    38! is 523022617466601111760007224100074291200000000
    39! is 20397882081197443358640281739902897356800000000
    40! is 815915283247897734345611269596115894272000000000

### 17.3.2 Die Klasse BigDecimal

Die Klasse `BigDecimal` kann beliebig genaue Fließkommazahlen darstellen. Sie bestehen aus einer Ziffernfolge (die als Objekt vom Typ `BigInteger` gespeichert ist) und einer Skalierung, die als nicht-negative Ganzzahl gespeichert wird. Die Skalierung bestimmt die Anzahl der Nachkommastellen. Der Wert der Zahl ergibt sich aus der Formel Unskalierter Wert / (10 Skalierung).

Die Instanzierung eines `BigDecimal`-Objekts kann analog zur Klasse `BigInteger` durch Übergabe eines Strings an den Konstruktor erfolgen. Dabei ist neben dem ganzzahligen Teil zusätzlich ein Dezimalpunkt und ein Gleitkommateil erlaubt. Die Anzahl der Nachkommastellen bestimmt die Skalierung. Alternativ kann das Objekt auch aus einem `BigInteger` oder einem `double` konstruiert werden:

    public BigDecimal(BigInteger val)
    public BigDecimal(double val)
    public BigDecimal(String val)
| java.math.BigDecimal

`BigDecimal` stellt elementare arithmetischen Funktionen zur Verfügung:

    public BigDecimal add(BigDecimal val)
    public BigDecimal subtract(BigDecimal val)
    public BigDecimal multiply(BigDecimal val)
    public BigDecimal divide(BigDecimal val, int roundingMode)

    public BigDecimal abs()
    public BigDecimal negate()
    public int signum()

    public BigDecimal min(BigDecimal val)
    public BigDecimal max(BigDecimal val)
| java.math.BigDecimal

Ihr Verhalten entspricht weitgehend dem bei `BigInteger` beschriebenen. Eine Ausnahme bildet die Methode `divide`, denn sie benötigt zusätzlich eine Konstante, die die Art der Rundung (falls erforderlich) bestimmt:

- `ROUND_CEILING`
- `ROUND_DOWN`
- `ROUND_FLOOR`
- `ROUND_HALF_DOWN`
- `ROUND_HALF_EVEN`
- `ROUND_HALF_UP`
- `ROUND_UNNECESSARY`
- `ROUND_UP`

Auch die Konvertierungs- und Vergleichsmethoden entsprechen denen der Klasse `BigInteger`:

    public int compareTo(BigDecimal val)
    public boolean equals(Object x)

    public String toString()

    public int intValue()
    public long longValue()
    public float floatValue()
    public double doubleValue()
| java.math.BigDecimal

Mit Hilfe der Methoden `scale` und `setScale` kann die Skalierung abgefragt bzw. ein neues Objekt mit geänderter Skalierung erzeugt werden:

    public int scale()

    public BigDecimal setScale(int scale)
    public BigDecimal setScale(int scale, int roundingMode)
| java.math.BigDecimal

Das Ändern der Skalierung läßt den numerischen Wert des Objekts intakt und verändert lediglich die Anzahl der darstellbaren Dezimalstellen. Soll diese verkleinert werden, muß die zweite Variante von `setScale` verwendet und eine passende Rundungskonstante übergeben werden. Soll die Anzahl der Dezimalstellen vergrößert werden, kann die erste Variante verwendet werden.

Zusätzlich gibt es zwei Methoden, mit denen der Dezimalpunkt um eine bestimmte Anzahl Stellen nach links oder rechts verschoben werden kann, also eine Multiplikation bzw. Division mit einer Zehnerpotenz ausgeführt wird:

    public BigDecimal movePointLeft(int n)
    public BigDecimal movePointRight(int n)
| java.math.BigDecimal

Zum Abschluß wollen wir uns ein Beispielprogramm ansehen, das die Quadratwurzel der Zahl 2 in (theoretisch) beliebiger Genauigkeit errechnen kann:

    001 /* Listing1703.java */
    002
    003 import java.math.*;
    004
    005 public class Listing1703
    006 {
    007   public static final BigDecimal ZERO = new BigDecimal("0");
    008   public static final BigDecimal ONE  = new BigDecimal("1");
    009   public static final BigDecimal TWO  = new BigDecimal("2");
    010
    011   public static BigDecimal sqrt(BigDecimal x, int digits)
    012   {
    013     BigDecimal zero = ZERO.setScale(digits + 10);
    014     BigDecimal one  = ONE.setScale(digits + 10);
    015     BigDecimal two  = TWO.setScale(digits + 10);
    016     BigDecimal maxerr = one.movePointLeft(digits);
    017     BigDecimal lower = zero;
    018     BigDecimal upper = x.compareTo(one) <= 0 ? one : x;
    019     BigDecimal mid;
    020     while (true) {
    021       mid = lower.add(upper).divide(two, BigDecimal.ROUND_HALF_UP);
    022       BigDecimal sqr = mid.multiply(mid);
    023       BigDecimal error = x.subtract(sqr).abs();
    024       if (error.compareTo(maxerr) <= 0) {
    025         break;
    026       }
    027       if (sqr.compareTo(x) < 0) {
    028         lower = mid;
    029       } else {
    030         upper = mid;
    031       }
    032     }
    033     return mid;
    034   }
    035
    036   public static void main(String[] args)
    037   {
    038     BigDecimal sqrtTwo = sqrt(TWO, 100);
    039     BigDecimal apxTwo  = sqrtTwo.multiply(sqrtTwo);
    040     System.out.println("sqrt(2): " + sqrtTwo.toString());
    041     System.out.println("check  : " + apxTwo.toString());
    042   }
    043 }
| Listing1703.java

Listing 17.3: Anwendung der Klasse BigDecimal

Das Programm arbeitet mit einer Intervallschachtelung. Dazu werden zunächst passende Unter- und Obergrenzen gesucht, so daß das Quadrat der Untergrenze auf jeden Fall kleiner gleich und das Quadrat der Obergrenze größer oder gleich der gesuchten Zahl ist. Nun wird der Wert genau in der Mitte zwischen beiden Punkten quadriert und mit dem gesuchten Ergebnis verglichen. Ist er größer, wird die Mitte als neue Obergrenze verwendet, andernfalls als neue Untergrenze. Diese Iteration wird solange fortgesetzt, bis der Fehler kleiner als der maximal erlaubte ist.

|  | Das Beispielprogramm berechnet das Ergebnis auf etwa 100 Stellen nach dem Komma. Dieser Wert kann prinzipiell beliebig vergrößert werden. Zu bedenken ist allerdings, daß dadurch die Laufzeit überproportional ansteigt. Zwar bleibt die Intervallschachtelung an sich performant, aber durch die größere Anzahl an zu verarbeitenden Dezimalstellen benötigt jeder einzelne Aufruf einer arithmetischen Methode mehr Rechenzeit. Zudem erfordert die höhere Genauigkeit insgesamt mehr Iterationen, so daß insgesamt das Laufzeitverhalten wohl quadratisch mit der Genauigkeitsanforderung wachsen dürfte. |  |
Hinweis

Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 3. Auflage, Addison Wesley, Version 3.0
<< | < | > | >> | API | © 1998-2002 Guido Krüger, http://www.javabuch.de