CodeGym /Java-Blog /Random-DE /BigDecimal in Java
Autor
Oleksandr Miadelets
Head of Developers Team at CodeGym

BigDecimal in Java

Veröffentlicht in der Gruppe Random-DE
Hallo! In der heutigen Lektion werden wir über große Zahlen sprechen. Nein, ich meine WIRKLICH GROSS. Die Tabelle der Wertebereiche für primitive Datentypen ist uns schon mehrfach begegnet. Es sieht aus wie das:
Primitiver Typ Größe im Speicher Wertebereich
Byte 8 Bit -128 bis 127
kurz 16 Bit -32768 bis 32767
verkohlen 16 Bit 0 bis 65536
int 32 Bit -2147483648 bis 2147483647
lang 64-Bit -9223372036854775808 bis 9223372036854775807
schweben 32 Bit (2 hoch -149) bis ((2 hoch -23) * 2 hoch 127)
doppelt 64-Bit (-2 hoch 63) bis ((2 hoch 63) - 1)
Boolescher Wert 8 (bei Verwendung in Arrays), 32 (wenn nicht in Arrays verwendet) richtig oder falsch
Der umfangreichste ganzzahlige Datentyp ist long . Bei Gleitkommazahlen ist es das Double. Aber was ist, wenn die Zahl, die wir brauchen, so groß ist, dass sie nicht einmal in eine lange Zeile passt? Der Long-Datentyp verfügt über einen recht großen Bereich möglicher Werte, ist jedoch immer noch auf 64 Bit begrenzt. Was müssen wir uns einfallen lassen, wenn unsere Very Large Number 100 Bits erfordert? Glücklicherweise müssen wir nichts erfinden. Für solche Fälle gibt es in Java zwei spezielle Klassen: BigInteger (für ganze Zahlen) und BigDecimal(für Gleitkommazahlen). Was macht sie besonders? Erstens haben sie theoretisch keine maximale Größe. Wir sagen „theoretisch“, weil es keine Computer mit unendlichem Speicher gibt. Und wenn Ihr Programm eine Zahl erstellt, die größer ist als der verfügbare Speicher, dann wird das Programm natürlich nicht funktionieren. Aber solche Fälle sind unwahrscheinlich. Als Ergebnis können wir sagen, dass BigInteger und BigDecimal Zahlen praktisch unbegrenzter Größe darstellen können. Wofür werden diese Klassen verwendet? Erstens für Berechnungen mit äußerst hohen Genauigkeitsanforderungen. Beispielsweise kann menschliches Leben von der Genauigkeit der Berechnungen in einigen Programmen (z. B. Software zur Steuerung von Flugzeugen, Raketen oder medizinischen Geräten) abhängen. Wenn also die 150. Dezimalstelle wichtig ist, dann BigDecimalist die beste Wahl. Darüber hinaus werden Objekte dieser Klasse häufig in der Finanzwelt eingesetzt, wo auch die genaue Berechnung selbst kleinster Werte äußerst wichtig ist. Wie arbeiten Sie mit BigInteger und BigDecimal Objekten und müssen Sie darüber Bescheid wissen? Objekte dieser Klassen werden wie folgt erstellt:

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       BigDecimal decimal = new BigDecimal("123.444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444");
       System.out.println(decimal);
   }
}
Die Übergabe einer Zeichenfolge an den Konstruktor ist nur eine mögliche Option. Hier verwenden wir Zeichenfolgen, da unsere Zahlen die Maximalwerte für long und double überschreiten und wir dem Compiler irgendwie erklären müssen, welche Zahl wir erstellen möchten :) Übergeben Sie einfach die Zahl 1111111111111111111111111111111111111111111111111111111111111111111111111111 111111111111111111111111111111111111111111111111111111111111111111 an den Konstruktor funktioniert nicht: Java wird versuchen, die übergebene Zahl in einen der primitiven Datentypen zu packen, aber sie passt in keinen von ihnen. Aus diesem Grund ist die Verwendung einer Zeichenfolge zur Übergabe der gewünschten Zahl eine gute Option. Beide Klassen können automatisch numerische Werte aus den übergebenen Strings extrahieren. Ein weiterer wichtiger Punkt, den Sie bei der Arbeit mit Klassen mit großen Zahlen beachten sollten, ist, dass ihre Objekte unveränderlich ( Immutable ) sind. Dank Ihrer Erfahrung mit der String- Klasse und den Wrapper-Klassen für primitive Typen (Integer, Long usw.) sind Sie bereits mit Unveränderlichkeit vertraut.

import java.math.BigInteger;

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       integer.add(BigInteger.valueOf(33333333));
       System.out.println(integer);

   }
}
Konsolenausgabe:

11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 
Wie zu erwarten ist, hat sich unsere Nummer nicht geändert. Um die Additionsoperation auszuführen, müssen Sie ein neues Objekt erstellen, um das Ergebnis der Operation zu erhalten.

import java.math.BigInteger;

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       BigInteger result = integer.add(BigInteger.valueOf(33333333));
       System.out.println(result);

   }
}
Konsolenausgabe:

11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111144444444
Sehen Sie, jetzt funktioniert alles so, wie es sollte :) Ist Ihnen übrigens aufgefallen, wie ungewöhnlich die Additionsoperation aussieht?

BigInteger result = integer.add(BigInteger.valueOf(33333333));
Dies ist ein weiterer wichtiger Punkt. Klassen mit großen Zahlen verwenden nicht die Operatoren + - * /. Stattdessen stellen sie eine Reihe von Methoden bereit. Machen wir uns mit den wichtigsten vertraut (eine vollständige Liste der Methoden finden Sie wie immer in der Oracle-Dokumentation: hier und hier ).
  1. Methoden für arithmetische Operationen: add() , subtract() , multiply() , Divide() . Mit diesen Methoden werden jeweils Addition, Subtraktion, Multiplikation und Division durchgeführt.

  2. doubleValue() , intValue() , floatValue() , longValue() usw. werden verwendet, um eine große Zahl in einen der primitiven Java-Typen umzuwandeln. Seien Sie vorsichtig, wenn Sie diese Methoden anwenden. Vergessen Sie nicht die Unterschiede in der Bitgröße!

    
    import java.math.BigInteger;
    
    public class Main {
    
       public static void main(String[] args) {
    
           BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
    
           long result = integer.longValue();
           System.out.println(result);
    
       }
    }
    

    Konsolenausgabe:

    
    8198552921648689607
    
  3. Mit min() und max() können Sie den Minimal- und Maximalwert zweier großer Zahlen ermitteln.
    Beachten Sie, dass diese Methoden nicht statisch sind!

    
    import java.math.BigInteger;
    
    public class Main {
    
       public static void main(String[] args) {
    
           BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
           BigInteger integer2 = new BigInteger("222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222");
    
           System.out.println(integer.max(integer2));
    
       }
    }
    

    Konsolenausgabe:

    
    222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
    

BigDecimal-Rundungsverhalten

Zu diesem Thema gibt es einen eigenen Abschnitt, da das Runden großer Zahlen und das Konfigurieren des Rundungsverhaltens nicht so einfach sind. Sie können die Methode setScale() verwenden , um die Anzahl der Dezimalstellen für eine BigDecimal festzulegen. Angenommen, wir möchten, dass die Zahl 111,5555555555 drei Nachkommastellen hat. Allerdings können wir nicht das erreichen, was wir wollen, indem wir die Zahl 3 als Argument an die setScale() Methode übergeben. Wie oben erwähnt, BigDecimaldient der Darstellung von Zahlen mit strengen Anforderungen an die Rechengenauigkeit. In der aktuellen Form hat unsere Zahl 10 Nachkommastellen. Wir wollen 7 davon weglassen und nur 3 behalten. Dementsprechend müssen wir zusätzlich zur Zahl 3 den Rundungsmodus bestehen. BigDecimal verfügt über insgesamt 8 Rundungsmodi. Das ist eine Menge! Aber wenn Sie die Präzision Ihrer Berechnungen wirklich verfeinern müssen, haben Sie alles, was Sie brauchen. Hier sind also die 8 Rundungsmodi, die BigDecimal bietet :
  1. ROUND_CEILING – rundet auf

    
    111.5555555555 -> setScale(3, ROUND_CEILING) -> 111.556
    
  2. ROUND_DOWN – rundet gegen Null

    
    111.5555555555 -> setScale(3, ROUND_DOWN) -> 111.555
    
  3. ROUND_FLOOR – rundet ab

    
     111.5555555555 -> setScale(3, ROUND_FLOOR) -> 111.555
    
    

  4. ROUND_HALF_UP – rundet auf, wenn die Zahl nach dem Dezimalpunkt >= 0,5 ist

    
    0.55 -> setScale(1, ROUND_HALF_UP) -> 0.6
    0.54 -> setScale(1, ROUND_HALF_UP) -> 0.5
    
  5. ROUND_HALF_DOWN – rundet auf, wenn die Zahl nach dem Dezimalpunkt > 0,5 ist

    
    0.55 -> setScale(1, ROUND_HALF_DOWN) -> 0.5
    0.56 -> setScale(1, ROUND_HALF_DOWN) -> 0.6
    
  6. ROUND_HALF_EVEN – Die Rundung hängt von der Zahl links vom Dezimalpunkt ab. Wenn die Zahl links gerade ist, wird abgerundet. Wenn die Zahl links vom Dezimalpunkt ungerade ist, wird aufgerundet.

    
    2.5 -> setScale(0, ROUND_HALF_EVEN) -> 2
    

    Die Zahl links von der Dezimalstelle ist 2 (gerade). Die Zahl wird abgerundet. Wir wollen 0 Dezimalstellen, also ist das Ergebnis 2.

    
    3.5 -> setScale(0, ROUND_HALF_EVEN) -> 4
    

    Die Zahl links vom Dezimalpunkt ist 3 (ungerade). Die Zahl wird aufgerundet. Wir wollen 0 Dezimalstellen, also ist das Ergebnis 4.

  7. ROUND_UNNECCESSARY – Dieser Modus wird verwendet, wenn Sie einer Methode einen Rundungsmodus übergeben müssen, die Zahl jedoch nicht gerundet werden muss. Wenn Sie versuchen, eine Zahl mit gesetztem ROUND_UNNECCESSARY-Modus zu runden, wird eine ArithmeticException ausgelöst.

    
    3.51 -> setScale(1, ROUND_UNNECCESSARY) -> ArithmeticException
    
  8. ROUND_UP – rundet von Null ab.

    
    111.5551 -> setScale(3, ROUND_UP) -> 111.556
    

Große Zahlen vergleichen

Das ist auch wichtig. Sie werden sich erinnern, dass wir die Methode equal() zum Vergleichen von Objekten in Java verwenden. Die Implementierung wird entweder von der Sprache selbst bereitgestellt (für Standard-Java-Klassen) oder vom Programmierer überschrieben. Bei BigDecimal Objekten wird die Verwendung der Methode equal() für Vergleiche jedoch nicht empfohlen. Dies liegt daran, dass die Methode BigDecimal.equals() nur dann „true“ zurückgibt, wenn die beiden Zahlen den gleichen Wert und die gleiche Skalierung haben: Vergleichen wir das Verhalten der Methode equal() für die Klassen Double und BigDecimal:

import java.math.BigDecimal;

public class Main {

   public static void main(String[] args) {

       Double a = 1.5;
       Double b = 1.50;

       System.out.println(a.equals(b));

       BigDecimal x = new BigDecimal("1.5");
       BigDecimal y = new BigDecimal("1.50");

       System.out.println(x.equals(y));
      
   }
}
Konsolenausgabe:

true 
false
Wie Sie sehen können, erwiesen sich für BigDecimal die Zahlen 1,5 und 1,50 als ungleich! Dies lag genau an den Besonderheiten der Implementierung der Methode equal() in der Klasse BigDecimal. Für einen genaueren Vergleich zweier BigDecimal Objekte ist es besser, die Methode CompareTo() zu verwenden :

import java.math.BigDecimal;

public class Main {

   public static void main(String[] args) {

       BigDecimal x = new BigDecimal("1.5");
       BigDecimal y = new BigDecimal("1.50");

       System.out.println(x.compareTo(y));

   }
}
Konsolenausgabe:

0
Die Methode compareTo() hat 0 zurückgegeben, was bedeutet, dass 1,5 und 1,50 gleich sind. Und das ist das Ergebnis, das wir erwartet haben! :) Damit ist unsere heutige Lektion abgeschlossen. Jetzt geht es wieder an die Aufgaben! :) :)
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION