Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger. 
Inhaltsverzeichnis
Vorwort
1 Java ist auch eine Sprache
2 Imperative Sprachkonzepte
3 Klassen und Objekte
4 Der Umgang mit Zeichenketten
5 Eigene Klassen schreiben
6 Objektorientierte Beziehungsfragen
7 Ausnahmen müssen sein
8 Äußere.innere Klassen
9 Besondere Typen der Java SE
10 Generics<T>
11 Lambda-Ausdrücke und funktionale Programmierung
12 Architektur, Design und angewandte Objektorientierung
13 Komponenten, JavaBeans und Module
14 Die Klassenbibliothek
15 Einführung in die nebenläufige Programmierung
16 Einführung in Datenstrukturen und Algorithmen
17 Einführung in grafische Oberflächen
18 Einführung in Dateien und Datenströme
19 Einführung ins Datenbankmanagement mit JDBC
20 Einführung in <XML>
21 Testen mit JUnit
22 Bits und Bytes und Mathematisches
23 Die Werkzeuge des JDK
A Java SE-Paketübersicht
Stichwortverzeichnis


Download:

- Beispielprogramme, ca. 35,4 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 22 Bits und Bytes und Mathematisches
Pfeil 22.1 Bits und Bytes *
Pfeil 22.1.1 Die Bit-Operatoren Komplement, Und, Oder und XOR
Pfeil 22.1.2 Repräsentation ganzer Zahlen in Java – das Zweierkomplement
Pfeil 22.1.3 Das binäre (Basis 2), oktale (Basis 8), hexadezimale (Basis 16) Stellenwertsystem
Pfeil 22.1.4 Auswirkung der Typumwandlung auf die Bit-Muster
Pfeil 22.1.5 Vorzeichenlos arbeiten
Pfeil 22.1.6 Die Verschiebeoperatoren
Pfeil 22.1.7 Ein Bit setzen, löschen, umdrehen und testen
Pfeil 22.1.8 Bit-Methoden der Integer- und Long-Klasse
Pfeil 22.2 Fließkomma-Arithmetik in Java
Pfeil 22.2.1 Spezialwerte für Unendlich, Null, NaN
Pfeil 22.2.2 Standardnotation und wissenschaftliche Notation bei Fließkommazahlen *
Pfeil 22.2.3 Mantisse und Exponent *
Pfeil 22.3 Die Eigenschaften der Klasse Math
Pfeil 22.3.1 Attribute
Pfeil 22.3.2 Absolutwerte und Vorzeichen
Pfeil 22.3.3 Maximum/Minimum
Pfeil 22.3.4 Runden von Werten
Pfeil 22.3.5 Rest der ganzzahligen Division *
Pfeil 22.3.6 Division mit Rundung Richtung negativ unendlich, alternativer Restwert *
Pfeil 22.3.7 Wurzel- und Exponentialmethoden
Pfeil 22.3.8 Der Logarithmus *
Pfeil 22.3.9 Winkelmethoden *
Pfeil 22.3.10 Zufallszahlen
Pfeil 22.4 Genauigkeit, Wertebereich eines Typs und Überlaufkontrolle *
Pfeil 22.4.1 Der größte und der kleinste Wert
Pfeil 22.4.2 Überlauf
Pfeil 22.4.3 Was bitte macht eine ulp?
Pfeil 22.5 Zufallszahlen: Random, SecureRandom, SplittableRandom
Pfeil 22.5.1 Die Klasse Random
Pfeil 22.5.2 Random-Objekte mit dem Samen aufbauen
Pfeil 22.5.3 Einzelne Zufallszahlen erzeugen
Pfeil 22.5.4 Pseudo-Zufallszahlen in der Normalverteilung *
Pfeil 22.5.5 Strom von Zufallszahlen generieren *
Pfeil 22.5.6 Die Klasse SecureRandom *
Pfeil 22.5.7 SplittableRandom *
Pfeil 22.6 Große Zahlen *
Pfeil 22.6.1 Die Klasse BigInteger
Pfeil 22.6.2 Beispiel: ganz lange Fakultäten mit BigInteger
Pfeil 22.6.3 Große Fließkommazahlen mit BigDecimal
Pfeil 22.6.4 Mit MathContext komfortabel die Rechengenauigkeit setzen
Pfeil 22.7 Mathe bitte strikt *
Pfeil 22.7.1 Strikte Fließkommaberechnungen mit strictfp
Pfeil 22.7.2 Die Klassen Math und StrictMath
Pfeil 22.8 Zum Weiterlesen
 

Zum Seitenanfang

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

 

Zum Seitenanfang

22.4.1Der 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 direkt nichts aus.

Bastelaufgabe

Warum sind die Ausgaben so, wie sie sind?

Listing 22.9DoubleFloatEqual.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

22.4.2Überlauf 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, Java hat keine eingebaute Überlaufkontrolle in der Sprache.

[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

Ü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 long multiplyExact(long x, long y)

  • static int toIntExact(long value)

Alle Methoden werfen eine ArithmeticException, 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 zur Ausnahme:

subtractExact( Integer.MIN_VALUE, 1 ); // inline ArithmeticException

In Math, aber nicht in StrictMath, gibt es außerdem:

class java.lang.Math
  • 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)

Kann wegen des Wertebereichs die Operation nicht durchgeführt werden, folgt wieder eine 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

22.4.3Was 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)/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) 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 sie kleiner, dann die nächstkleinere Zahl. Bei Gleichheit kommt die gleiche Zahl zurück.

Dazu ein weiteres Beispiel: Je größer die Zahlen werden, desto größer werden auch die Sprünge:

Methode

Rückgabe des 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 22.12Da das Vorzeichen in einem eigenen Bit gespeichert ist, haben negative oder positive Zahlen keine anderen Genauigkeiten.

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), 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. 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)

 


Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.

>> Zum Feedback-Formular
<< zurück

 

 


Copyright © Rheinwerk Verlag GmbH 2017

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