Rheinwerk Computing < openbook >


 
Inhaltsverzeichnis
Materialien
Vorwort
1 Java ist auch eine Sprache
2 Imperative Sprachkonzepte
3 Klassen und Objekte
4 Arrays und ihre Anwendungen
5 Der Umgang mit Zeichenketten
6 Eigene Klassen schreiben
7 Objektorientierte Beziehungsfragen
8 Ausnahmen müssen sein
9 Geschachtelte Typen
10 Besondere Typen der Java SE
11 Generics<T>
12 Lambda-Ausdrücke und funktionale Programmierung
13 Architektur, Design und angewandte Objektorientierung
14 Java Platform Module System
15 Die Klassenbibliothek
16 Einführung in die nebenläufige Programmierung
17 Einführung in Datenstrukturen und Algorithmen
18 Einführung in grafische Oberflächen
19 Einführung in Dateien und Datenströme
20 Einführung ins Datenbankmanagement mit JDBC
21 Bits und Bytes, Mathematisches und Geld
22 Testen mit JUnit
23 Die Werkzeuge des JDK
A Java SE-Module und Paketübersicht
Stichwortverzeichnis


Download:

- Listings, ca. 2,7 MB


Buch bestellen
Ihre Meinung?



Spacer
<< zurück
Java ist auch eine Insel von Christian Ullenboom

Einführung, Ausbildung, Praxis
Buch: Java ist auch eine Insel


Java ist auch eine Insel

Pfeil 21 Bits und Bytes, Mathematisches und Geld
Pfeil 21.1 Bits und Bytes
Pfeil 21.1.1 Die Bit-Operatoren Komplement, Und, Oder und XOR
Pfeil 21.1.2 Repräsentation ganzer Zahlen in Java – das Zweierkomplement
Pfeil 21.1.3 Das binäre (Basis 2), oktale (Basis 8), hexadezimale (Basis 16) Stellenwertsystem
Pfeil 21.1.4 Auswirkung der Typumwandlung auf die Bit-Muster
Pfeil 21.1.5 Vorzeichenlos arbeiten
Pfeil 21.1.6 Die Verschiebeoperatoren
Pfeil 21.1.7 Ein Bit setzen, löschen, umdrehen und testen
Pfeil 21.1.8 Bit-Methoden der Integer- und Long-Klasse
Pfeil 21.2 Fließkomma-Arithmetik in Java
Pfeil 21.2.1 Spezialwerte für Unendlich, Null, NaN
Pfeil 21.2.2 Standardnotation und wissenschaftliche Notation bei Fließkommazahlen *
Pfeil 21.2.3 Mantisse und Exponent *
Pfeil 21.3 Die Eigenschaften der Klasse Math
Pfeil 21.3.1 Attribute
Pfeil 21.3.2 Absolutwerte und Vorzeichen
Pfeil 21.3.3 Maximum/Minimum
Pfeil 21.3.4 Runden von Werten
Pfeil 21.3.5 Rest der ganzzahligen Division *
Pfeil 21.3.6 Division mit Rundung in Richtung negativ unendlich, alternativer Restwert *
Pfeil 21.3.7 Multiply-Accumulate
Pfeil 21.3.8 Wurzel- und Exponentialmethoden
Pfeil 21.3.9 Der Logarithmus *
Pfeil 21.3.10 Winkelmethoden *
Pfeil 21.3.11 Zufallszahlen
Pfeil 21.4 Genauigkeit, Wertebereich eines Typs und Überlaufkontrolle *
Pfeil 21.4.1 Der größte und der kleinste Wert
Pfeil 21.4.2 Überlauf und alles ganz exakt
Pfeil 21.4.3 Was bitte macht eine ulp?
Pfeil 21.5 Zufallszahlen: Random, SecureRandom und SplittableRandom
Pfeil 21.5.1 Die Klasse Random
Pfeil 21.5.2 Random-Objekte mit dem Samen aufbauen
Pfeil 21.5.3 Einzelne Zufallszahlen erzeugen
Pfeil 21.5.4 Pseudo-Zufallszahlen in der Normalverteilung *
Pfeil 21.5.5 Strom von Zufallszahlen generieren *
Pfeil 21.5.6 Die Klasse SecureRandom *
Pfeil 21.5.7 SplittableRandom *
Pfeil 21.6 Große Zahlen *
Pfeil 21.6.1 Die Klasse BigInteger
Pfeil 21.6.2 Beispiel: Ganz lange Fakultäten mit BigInteger
Pfeil 21.6.3 Große Fließkommazahlen mit BigDecimal
Pfeil 21.6.4 Mit MathContext komfortabel die Rechengenauigkeit setzen
Pfeil 21.6.5 Noch schneller rechnen durch mutable Implementierungen
Pfeil 21.7 Mathe bitte strikt *
Pfeil 21.7.1 Strikte Fließkommaberechnungen mit strictfp
Pfeil 21.7.2 Die Klassen Math und StrictMath
Pfeil 21.8 Geld und Währung
Pfeil 21.8.1 Geldbeträge repräsentieren
Pfeil 21.8.2 ISO 4217
Pfeil 21.8.3 Währungen in Java repräsentieren
Pfeil 21.9 Zum Weiterlesen
 

Zum Seitenanfang

21.4    Genauigkeit, Wertebereich eines Typs und Überlaufkontrolle * Zur vorigen ÜberschriftZur nächsten Überschrift

Die Datentypen in Java haben immer eine bestimmte Anzahl von Bytes, und somit ist der Wertebereich bekannt. Allerdings kann eine Operation aus diesem Wertebereich herauslaufen.

 

Zum Seitenanfang

21.4.1    Der größte und der kleinste Wert Zur vorigen ÜberschriftZur nächsten Überschrift

Für jeden primitiven Datentyp gibt es in Java eine eigene Klasse mit diversen Methoden und Konstanten. Die Klassen Byte, Short, Integer, Long, Float und Double besitzen die Konstanten MIN_VALUE und MAX_VALUE für den minimalen und maximalen Wertebereich. Die Klassen Float und Double verfügen zusätzlich über die wichtigen Konstanten NEGATIVE_INFINITY und POSITIVE_INFINITY für minus und plus unendlich und NaN (Not a Number, undefiniert).

[»]  Hinweis

Integer.MIN_VALUE steht mit –2.147.483.648 für den kleinsten Wert, den die Ganzzahl annehmen kann. Double.MIN_VALUE steht jedoch für die kleinste positive Zahl (beste Näherung an 0), die ein Double darstellen kann (4.9E–324).

Wenn uns beim Wort double im Vergleich zu float eine »doppelte Genauigkeit« über die Lippen kommt, müssen wir mit der Aussage vorsichtig sein, denn double bietet zumindest nach der Anzahl der Bits eine mehr als doppelt so präzise Mantisse. Über die Anzahl der Nachkommastellen sagt das jedoch nichts aus.

[zB]  Bastelaufgabe

Warum sind die Ausgaben so, wie sie sind?

Listing 21.9    src/main/java/com/tutego/insel/math/DoubleFloatEqual.java, main()

double d1 = 0.02d;

float f1 = 0.02f;

System.out.println( d1 == f1 ); // false

System.out.println( (float) d1 == f1 ); // true



double d2 = 0.02f;

float f2 = 0.02f;

System.out.println( d2 == f2 ); // true
 

Zum Seitenanfang

21.4.2    Überlauf und alles ganz exakt Zur vorigen ÜberschriftZur nächsten Überschrift

Bei einigen mathematischen Fragestellungen muss sich feststellen lassen, ob Operationen wie die Addition, Subtraktion oder Multiplikation den Zahlenbereich sprengen, also etwa den Ganzzahlenbereich eines Integers von 32 Bit verlassen. Passt das Ergebnis einer Berechnung nicht in den Wertebereich einer Zahl, so wird dieser Fehler standardmäßig nicht von Java angezeigt; weder der Compiler noch die Laufzeitumgebung melden dieses Problem. Es gibt auch keine Ausnahme: In Java existiert keine eingebaute Überlaufkontrolle.

[zB]  Beispiel

Mathematisch gilt a × a ÷ a = a, also zum Beispiel 100.000 × 100.000 ÷ 100.000 = 100.000. In Java ist das anders, da wir bei 100.000 × 100.000 einen Überlauf im int haben.

System.out.println( 100_000 * 100_000 / 100_000 );     // 14100

liefert daher 14100. Wenn wir den Datentyp auf long erhöhen, indem wir hinter ein 100_000 ein L setzen, sind wir bei dieser Multiplikation noch sicher, da ein long das Ergebnis aufnehmen kann:

System.out.println( 100_000L * 100_000 / 100_000 );    // 100000

Multiplizieren von int-Ganzzahlen

Der *-Operator führt bei int keine Anpassung an den Datentypen durch, sodass die Multiplikation von zwei ints wiederum int liefert. Doch das Produkt kann schnell aus dem Wertebereich laufen, sodass es zum Überlauf kommt. Selbst wenn das Produkt in eine long-Variable geschrieben wird, erfolgt die Konvertierung von int in long erst nach der Multiplikation:

int  i = Integer.MAX_VALUE * Integer.MAX_VALUE;

long l = Integer.MAX_VALUE * Integer.MAX_VALUE;

System.out.println( i ); // 1

System.out.println( l ); // 1

Sollen zwei ints ohne Überlauf multipliziert werden, ist einer der beiden Faktoren auf long anzupassen, damit die Berechnung zum korrekten Ergebnis 4611686014132420609 führt.

System.out.println( Integer.MAX_VALUE * (long) Integer.MAX_VALUE );

System.out.println( (long) Integer.MAX_VALUE * Integer.MAX_VALUE );

Da diese Typumwandlung schnell vergessen werden kann und nicht besonders explizit ist, bieten ab Java 9 die Klassen Math und StrictMath die statische Methode long multiplyFull(int x, int y), die für uns über (long)x * (long)y die Typumwandlung vornimmt.

Multiplizieren von long-Ganzzahlen

Es gibt keinen primitiven Datentyp, der mehr als 64 Bit (8 Byte) hat, sodass das Ergebnis von long * long mit seinen 128 Bit nur in ein BigInteger komplett passt. Allerdings erlaubt eine Methode, die oberen 64 Bit einer long-Multiplikation getrennt zu erfragen, und zwar ab Java 9 mit der Methode multiplyHigh(long x, long y) in Math und StrictMath – wobei StrictMath nur auf Math leitet.

[zB]  Beispiel
BigInteger v = BigInteger.valueOf( Long.MAX_VALUE )

.multiply( BigInteger.valueOf( Long.MAX_VALUE ) );

System.out.println( v ); // 85070591730234615847396907784232501249



long lowLong = Long.MAX_VALUE * Long.MAX_VALUE;

long highLong = Math.multiplyHigh( Long.MAX_VALUE, Long.MAX_VALUE );

BigInteger w = BigInteger.valueOf( highLong )

.shiftLeft( 64 )

.add( BigInteger.valueOf( lowLong ) );

System.out.println( w ); // 85070591730234615847396907784232501249

Überlauf erkennen

Bestimmte Methoden in Math und StrictMath ermöglichen eine Überlauferkennung:

class java.lang.Math

class java.lang.StrictMath
  • static int addExact(int x, int y)

  • static long addExact(long x, long y)

  • static int subtractExact(int x, int y)

  • static long subtractExact(long x, long y)

  • static int multiplyExact(int x, int y)

  • static int multiplyExact(long x, int y)

  • static long multiplyExact(long x, long y)

  • static int toIntExact(long value)

  • static int incrementExact(int a)

  • static long incrementExact(long a)

  • static int decrementExact(int a)

  • static long decrementExact(long a)

  • static int negateExact(int a)

  • static long negateExact(long a)

Alle Methoden lösen eine ArithmeticException aus, falls die Operation nicht durchführbar ist – die letzte zum Beispiel, wenn (int)value != value ist. Leider deklariert Java keine Unterklassen wie UnderflowException oder OverflowException, und Java meldet nur alles vom Typ ArithmeticException mit der Fehlermeldung »xxx overflow«, auch wenn es eigentlich ein Unterlauf ist.

[zB]  Beispiel

Von der kleinsten Ganzzahl mit subtractExact(…) eins abzuziehen, führt zu einer Ausnahme:

subtractExact( Integer.MIN_VALUE, 1 );    // inline image ArithmeticException
[»]  Vergleich mit C#

C# verhält sich genauso wie Java und reagiert standardmäßig nicht auf einen Überlauf. Es gibt jedoch spezielle checked-Blöcke, die eine OverflowException melden, wenn es bei arithmetischen Grundoperationen zu einem Überlauf kommt. Folgendes löst diese Ausnahme aus: checked { int val = int.MaxValue; val++; }. Solche checked-Blöcke gibt es in Java nicht – wer diese besondere Überlaufkontrolle braucht, muss die Methoden nutzen und ein val++ dann auch umschreiben zu Math.addExact(val, 1) bzw. Math.incrementExact(val).

 

Zum Seitenanfang

21.4.3    Was bitte macht eine ulp? Zur vorigen ÜberschriftZur nächsten Überschrift

Die Math-Klasse bietet sehr spezielle Methoden, die für diejenigen interessant sind, die sich sehr genau mit Rechen(un)genauigkeiten beschäftigen und mit numerischen Näherungen arbeiten.

Der Abstand von einer Fließkommazahl zur nächsten ist durch den internen Aufbau nicht immer gleich. Wie groß genau der Abstand einer Zahl zur nächstmöglichen ist, zeigt ulp( double) bzw. ulp(float). Der lustige Methodenname ist eine Abkürzung für Unit in the Last Place. Was genau denn die nächsthöhere/-niedrigere Zahl ist, ermitteln die Methoden nextUp(float|double) und nextDown(float|double), die auf nextAfter(…) zurückgreifen.

[zB]  Beispiel

Was kommt nach und vor 1?

System.out.printf( "%.16f%n", Math.nextUp( 1 ) );

System.out.printf( "%.16f%n", Math.nextDown( 1 ) );

System.out.printf( "%.16f%n", Math.nextAfter( 1, Double.POSITIVE_INFINITY ) );

System.out.printf( "%.16f%n", Math.nextAfter( 1, Double.NEGATIVE_INFINITY ) );

Die Ausgabe ist:

1,000000119209289

0,9999999403953552

1,0000001192092896

0,9999999403953552

nextUp(d) ist eine Abkürzung für nextAfter(d, Double.POSITIVE_INFINITY) und nextDown(d) ist eine Abkürzung für nextAfter(d, Double.NEGATIVE_INFINITY). Ist das zweite Argument von Math.nextAfter(…) größer als das erste, dann wird die nächstgrößere Zahl zurückgegeben; ist das zweite Argument kleiner, dann die nächstkleinere Zahl. Bei Gleichheit kommt die gleiche Zahl zurück.

Methode

Rückgabe der ulp

Math.ulp( 0.00001 )

0,000000000000000000001694065895

Math.ulp( –1 )

0,00000011920928955078125

Math.ulp( 1 )

0,00000011920928955078125

Math.ulp( 2 )

0,0000002384185791015625

Math.ulp( 10E30 )

1125899906842624

Tabelle 21.12    Beispiel: Je größer die Zahlen werden, desto größer werden die Sprünge.

Ein Quantum Ungenauigkeit

Die üblichen mathematischen Fließkommaoperationen haben eine ulp von ½. Das ist so genau wie möglich. Um wie viel ulp die Math-Methoden vom echten Resultat abweichen können, steht in der Javadoc. Rechenfehler lassen sich insbesondere bei komplexen Methoden nicht vermeiden. So darf sin(double) eine mögliche Ungenauigkeit von 1 ulp haben, atan2(double, double) von maximal 2 ulp und sinh(double), cosh(double) sowie tanh(double) von 2,5 ulp.

Die ulp(…)-Methode ist für das Testen interessant, denn mit ihr lassen sich Abweichungen immer in der passenden Größenordnung realisieren. Bei kleinen Zahlen ergibt eine Differenz von vielleicht 0,001 einen Sinn, bei größeren Zahlen kann die Toleranz größer sein.

Java deklariert in den Klassen Double und Float drei besondere Konstanten. Sie lassen sich gut mit nextAfter(…) erklären. Wir sehen das hier am Beispiel von Double:

  • MIN_VALUE = nextUp(0.0) = Double.longBitsToDouble(0x0010000000000000L)

  • MIN_NORMAL = MIN_VALUE/(nextUp(1.0)-1.0) = Double.longBitsToDouble(0x1L)

  • MAX_VALUE = nextAfter(POSITIVE_INFINITY, 0.0) =

       Double.longBitsToDouble(0x7fefffffffffffffL)

 


Ihre Meinung?

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de

<< zurück
 Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Java ist auch eine Insel Java ist auch eine Insel

Jetzt Buch bestellen


 Buchempfehlungen
Zum Rheinwerk-Shop: Captain CiaoCiao erobert Java

Captain CiaoCiao erobert Java




Zum Rheinwerk-Shop: Java SE 9 Standard-Bibliothek

Java SE 9 Standard-Bibliothek




Zum Rheinwerk-Shop: Algorithmen in Java

Algorithmen in Java




Zum Rheinwerk-Shop: Objektorientierte Programmierung

Objektorientierte Programmierung




 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und in die Schweiz

InfoInfo



 

 


Copyright © Rheinwerk Verlag GmbH 2021

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.

 

[Rheinwerk Computing]



Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de



Cookie-Einstellungen ändern