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 Exceptions
7 Äußere.innere Klassen
8 Besondere Klassen der Java SE
9 Generics<T>
10 Architektur, Design und angewandte Objektorientierung
11 Die Klassenbibliothek
12 Einführung in die nebenläufige Programmierung
13 Einführung in Datenstrukturen und Algorithmen
14 Einführung in grafische Oberflächen
15 Einführung in Dateien und Datenströme
16 Einführung in die <XML>-Verarbeitung mit Java
17 Einführung ins Datenbankmanagement mit JDBC
18 Bits und Bytes und Mathematisches
19 Die Werkzeuge des JDK
A Die Klassenbibliothek
Stichwort

Download:
- Aufgaben, ca. 1,1 MB
- Programme, ca. 12,8 MB

Buch bestellen
Ihre Meinung?

Spacer
Java ist auch eine Insel von Christian Ullenboom
Das umfassende Handbuch
Buch: Java ist auch eine Insel

Java ist auch eine Insel
Galileo Computing
1308 S., 10., aktualisierte Auflage, geb., mit DVD
ca. 49,90 Euro, ISBN 978-3-8362-1802-3
Pfeil 18 Bits und Bytes und Mathematisches
Pfeil 18.1 Bits und Bytes *
Pfeil 18.1.1 Die Bit-Operatoren Komplement, Und, Oder und Xor
Pfeil 18.1.2 Repräsentation ganzer Zahlen in Java – das Zweierkomplement
Pfeil 18.1.3 Das binäre (Basis 2), oktale (Basis 8), hexadezimale (Basis 16) Stellenwertsystem
Pfeil 18.1.4 Auswirkung der Typanpassung auf die Bitmuster
Pfeil 18.1.5 byte als vorzeichenlosen Datentyp nutzen
Pfeil 18.1.6 Die Verschiebeoperatoren
Pfeil 18.1.7 Ein Bit setzen, löschen, umdrehen und testen
Pfeil 18.1.8 Bit-Methoden der Integer- und Long-Klasse
Pfeil 18.2 Fließkommaarithmetik in Java
Pfeil 18.2.1 Spezialwerte für Unendlich, Null, NaN
Pfeil 18.2.2 Standard-Notation und wissenschaftliche Notation bei Fließkommazahlen *
Pfeil 18.2.3 Mantisse und Exponent *
Pfeil 18.3 Die Eigenschaften der Klasse Math
Pfeil 18.3.1 Attribute
Pfeil 18.3.2 Absolutwerte und Vorzeichen
Pfeil 18.3.3 Maximum/Minimum
Pfeil 18.3.4 Runden von Werten
Pfeil 18.3.5 Wurzel- und Exponentialmethoden
Pfeil 18.3.6 Der Logarithmus *
Pfeil 18.3.7 Rest der ganzzahligen Division *
Pfeil 18.3.8 Winkelmethoden *
Pfeil 18.3.9 Zufallszahlen
Pfeil 18.4 Genauigkeit, Wertebereich eines Typs und Überlaufkontrolle *
Pfeil 18.4.1 Behandlung des Überlaufs
Pfeil 18.4.2 Was bitte macht ein ulp?
Pfeil 18.5 Mathe bitte strikt *
Pfeil 18.5.1 Strikte Fließkommaberechnungen mit strictfp
Pfeil 18.5.2 Die Klassen Math und StrictMath
Pfeil 18.6 Die Random-Klasse
Pfeil 18.6.1 Objekte mit dem Samen aufbauen
Pfeil 18.6.2 Zufallszahlen erzeugen
Pfeil 18.6.3 Pseudo-Zufallszahlen in der Normalverteilung *
Pfeil 18.7 Große Zahlen *
Pfeil 18.7.1 Die Klasse BigInteger
Pfeil 18.7.2 Methoden von BigInteger
Pfeil 18.7.3 Ganz lange Fakultäten
Pfeil 18.7.4 Große Fließkommazahlen mit BigDecimal
Pfeil 18.7.5 Mit MathContext komfortabel die Rechengenauigkeit setzen
Pfeil 18.8 Zum Weiterlesen

Rheinwerk Computing - Zum Seitenanfang

18.4 Genauigkeit, Wertebereich eines Typs und Überlaufkontrolle *Zur 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 –2147483648 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 18.7: 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


Rheinwerk Computing - Zum Seitenanfang

18.4.1 Behandlung des ÜberlaufsZur nächsten ÜberschriftZur vorigen Überschrift

Bei einigen mathematischen Fragestellungen müssen Sie feststellen können, 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 nicht von Java angezeigt; weder der Compiler noch die Laufzeitumgebung melden dieses Problem. Es gibt auch keine Ausnahme.

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( 100000 * 100000 / 100000 );     // 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( 100000L * 100000 / 100000 );    // 100000

Überlauf erkennen

Für die Operationen Addition und Subtraktion lässt sich das noch ohne allzu großen Aufwand implementieren. Wir vergleichen dazu zunächst das Ergebnis mit den Konstanten Integer.MAX_VALUE und Integer.MIN_VALUE. Natürlich muss der Vergleich so umgeformt werden, dass dabei kein Überlauf auftritt, also a + b > Integer.MAX_VALUE ist. Überschreiten die Werte diese maximalen Werte, ist die Operation nicht ohne Fehler möglich, und wir setzen das Flag canAdd auf false. Hier die Programmzeilen für die Addition:

if ( a >=0 && b >= 0 )
if ( ! (b <= Integer.MAX_VALUE – a) )
canAdd = false;
if ( a < 0 && b < 0 )
if ( ! (b >= Integer.MIN_VALUE – a) )
canAdd = false;

Bei der Multiplikation gibt es zwei Möglichkeiten: Zunächst einmal lässt sich die Multiplikation als Folge von Additionen darstellen. Dann ließe sich wiederum der Test mit der Konstanten Integer.XXX_VALUE durchführen. Diese Lösung scheidet jedoch wegen der Geschwindigkeit aus. Der andere Weg sieht eine Umwandlung nach long vor. Das Ergebnis wird zunächst als long berechnet und anschließend mit dem Ganzzahlwert vom Typ int verglichen.

Dies funktioniert jedoch nur mit Datentypen, die kleiner als long sind. long selbst fällt heraus, da es keinen Datentyp gibt, der größer ist. Mit ein wenig Rechenungenauigkeit würde ein double jedoch weiterhelfen, und bei präziserer Berechnung kann BigInteger helfen. Bei der Multiplikation im Wertebereich int lässt sich ähnlich wie bei der Addition auch b > Integer.MAX_VALUE / a schreiben. Bei b == Integer.MAX_VALUE / a muss ein Test genau zeigen, ob das Ergebnis in den Wertebereich passt.

Die eigene statische Methode canMulLong() soll bei der Frage nach dem Überlauf helfen:

Listing 18.8: Overflow.java

import java.math.BigInteger;

public class Overflow
{
private final static BigInteger MAX = BigInteger.valueOf( Long.MAX_VALUE );

public static boolean canMulLong( long a, long b )
{
BigInteger bigA = BigInteger.valueOf( a );
BigInteger bigB = BigInteger.valueOf( b );

return bigB.multiply( bigA ).compareTo( MAX ) <= 0;
}

public static void main( String[] args )
{
System.out.println( canMulLong(Long.MAX_VALUE/2, 2) ); // true
System.out.println( Long.MAX_VALUE/2 * 2 ); // 9223372036854775806
System.out.println( canMulLong(Long.MAX_VALUE/2 + 1, 2) ); // false
System.out.println( (Long.MAX_VALUE/2 + 1) * 2 ); //-9223372036854775808
}
}
Hinweis

Wenn der Compiler beziehungsweise die JVM genau das macht, was wir uns wünschen, so würde auch ein return a * b / b == a; reichen. Doch eine JVM kann das zu return a == a; optimieren und somit zu return true; machen, sodass der Test nicht funktioniert.


Rheinwerk Computing - Zum Seitenanfang

18.4.2 Was bitte macht ein ulp?Zur vorigen Ü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) beziehungsweise 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(double)/nextUp(float), die auf nextAfter() zurückgreifen.

Beispiel

Was kommt nach und vor 1:

System.out.printf( "%.16f%n", Math.nextUp( 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,0000001192092896
1,0000001192092896
0,9999999403953552
nextUp() ist eine Abkürzung wie für den Ausdruck in der zweiten Zeile. 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.

Tabelle 18.11: Da das Vorzeichen in einem extra Bit gespeichert ist, haben negative
oder positive Zahlen keine anderen Genauigkeiten.

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

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() eine mögliche Ungenauigkeit von 1 ulp haben, atan2() von maximal 2 ulp und sinh(), chosh(), tanh() 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
  Zum Katalog
Zum Katalog: Java ist auch eine Insel





Java ist auch eine Insel
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Katalog: Java ist auch eine Insel






 Java ist auch
 eine Insel


Zum Katalog: Java SE Bibliotheken






 Java SE Bibliotheken


Zum Katalog: Professionell entwickeln mit Java EE 7






 Professionell
 entwickeln mit
 Java EE 7


Zum Katalog: Einstieg in Eclipse






 Einstieg in
 Eclipse


Zum Katalog: Einstieg in Java






 Einstieg in
 Java


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo




Copyright © Rheinwerk Verlag GmbH 2011
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