5.4 Die Eigenschaften der Klasse Math 

Die Klasse java.lang.Math ist eine typische Utility-Klasse, die nur statische Funktionen (beziehungsweise Attribute) hat. Mit einem privaten Konstruktor lassen sich eben keine Exemplare (so leicht) von Math erzeugen ...
5.4.1 Attribute 

Die Math-Klasse besitzt zwei statische Attribute:
class java.lang.Math |
- static final double E Die Eulersche Zahl e = 2.7182818284590452354.
- static final double PI Die Kreiszahl Pi = 3.14159265358979323846. [Wer noch auf der Suche nach einer völlig unsinnigen Information ist: Die einmilliardste Stelle hinter dem Komma von Pi ist eine Neun. ]
5.4.2 Absolutwerte und Maximum/Minimum 

Die abs()-Funktionen liefern den Betrag des Arguments (mathematische Betragsfunktion: y = |x|). Sollte ein negativer Wert als Argument übergeben werden, wandelt ihn abs() in einen positiven Wert um.
class java.lang.Math |
- static int abs( int x ), static long abs( long x )
- static float abs( float x ), static double abs( double x )
|
Die max()-Funktionen liefern den größeren der übergebenen Werte. Die min()-Funktionen liefern den kleineren von zwei Werten als Rückgabewert.
class java.lang.Math |
- static int max( int x, int y ), static long max( long x, long y )
- static float max( float x, float y ), static double max( double x, double y )
- static int min( int x, int y ), static long min( long x, long y )
- static float min( float x, float y ), static double min( double x, double y )
5.4.3 Winkelfunktionen 

Die Math-Klasse stellt einige Winkelfunktionen und ihre Umkehrungen zur Verfügung. Im Gegensatz zur bekannten Schulmathematik werden die Winkel für sin(), cos(), tan() im Bogenmaß (2*Pi entspricht einem Vollkreis) und nicht im Gradmaß (360 Grad entspricht einem Vollkreis) übergeben.
class java.lang.Math |
- static double sin( double x ) Liefert den Sinus von x.
- static double cos( double x ) Liefert den Kosinus von x.
- static double tan( double x ) Liefert den Tangens von x.
Die Arcus-Funktionen sind die Umkehrfunktionen zu den trigonometrischen Funktionen. Das Argument ist kein Winkel, sondern zum Beispiel bei asin() der Sinuswert zwischen –1 und 1. Das Ergebnis ist dann ein Winkel im Bogenmaß, etwa zwischen -Pi/2 und Pi/2.
class java.lang.Math |
- static double asin( double x ) Liefert den Arcus-Sinus von x, wobei -Pi/2 <= x <= Pi/2.
- static double acos( double x ) Liefert den Arcus-Kosinus von x, wobei 0 <= x <= Pi.
- static double atan( double x ) Liefert den Arcus-Tangens von x, wobei -Pi/2 <= x <= Pi/2.
- static atan2( double x, double y ) Liefert bei der Konvertierung von Rechteckkoordinaten in Polarkoordinaten den Winkel theta, also eine Komponente des Polarkoordinaten-Tupels. Die Methode berücksichtigt das Vorzeichen der Parameter x und y, und der freie Schenkel des Winkels befindet sich im richtigen Quadranten.
Hyperbolicus-Funktionen bietet Java über sinh(), tanh() und cosh().
Zur Umwandlung eines Winkels von Gradmaß in Bogenmaß und umgekehrt existieren zwei Funktionen.
class java.lang.Math |
- static double toRadians( double angdeg ) Gradmaß in Bogenmaß umwandeln
- static double toDegrees( double angrad ) Winkel vom Bogenmaß in Gradmaß umwandeln
5.4.4 Runden von Werten 

Für die Rundung von Werten bietet die Klasse Math fünf Methoden:
class java.lang.Math |
- double ceil( double )
- double floor( double )
- int round( float ), long round( double )
- double rint( double )
Auf- und Abrunden mit ceil() und floor()
Die Methode ceil() dient zum Aufrunden und liefert die nächsthöhere Ganzzahl (jedoch als double, nicht long), wenn die Zahl nicht schon eine ganze Zahl ist; die Funktion floor() rundet auf die nächst niedrige Ganzzahl ab.
Listing 5.3 RoundingDemo.java, Ausschnitt
System.out.println( Math.ceil(-99.1) ); // –99.0 System.out.println( Math.floor(-99.1) ); // –100.0 System.out.println( Math.ceil(-99) ); // –99.0 System.out.println( Math.floor(-99) ); // –99.0 System.out.println( Math.ceil(-.5) ); // –0.0 System.out.println( Math.floor(-.5) ); // –1.0 System.out.println( Math.ceil(-.01) ); // –0.0 System.out.println( Math.floor(-.01) ); // –1.0 System.out.println( Math.ceil(0.1) ); // 1.0 System.out.println( Math.floor(0.1) ); // 0.0 System.out.println( Math.ceil(.5) ); // 1.0 System.out.println( Math.floor(.5) ); // 0.0 System.out.println( Math.ceil(99) ); // 99.0 System.out.println( Math.floor(99) ); // 99.0
Die Methoden haben auf ganze Zahlen keine Auswirkung.
round()
Die Funktion round(double) rundet kaufmännisch auf die nächste Ganzzahl vom Typ long – bzw. rund(float) auf die Ganzzahl vom Typ int. Ganze Zahlen werden nicht aufgerundet. Wir können round()zur Typumwandlung einsetzen, als Gegenstück zu (long) d, und d ist ein double, das immer abrundet. Ein Beispiel zu round():
Listing 5.4 RoundingDemo.java, Ausschnitt
System.out.println( Math.round(1.01) ); // 1 System.out.println( Math.round(-2.1) ); // –2 System.out.println( Math.round(30) ); // 30
public static long round( double a ) { return (int) floor( a + 0.5f ); } |
rint()
rint() ist mit round() vergleichbar, nur ist es im Gegensatz zu round() gerechnet, was bedeutet, dass rint() bei 0,5 in Abhängigkeit davon, ob die benachbarte Zahl ungerade oder gerade ist, auf- oder abrundet.
Listing 5.5 RoundingDemo.java, Ausschnitt
System.out.println( Math.round(-1.5) ); // –1 System.out.println( Math.rint( –1.5) ); // –2.0 System.out.println( Math.round(-2.5) ); // –2 System.out.println( Math.rint( –2.5) ); // –2.0 System.out.println( Math.round( 1.5) ); // 2 System.out.println( Math.rint( 1.5) ); // 2.0 System.out.println( Math.round( 2.5) ); // 3 System.out.println( Math.rint( 2.5) ); // 2.0
Mit dem konsequenten Aufrunden pflanzen sich natürlich auch Fehler ungeschickter fort als mit dieser 50/50-Strategie.
|
Listing 5.6 Round2Scales.java
class Round2Scales { public static double roundScale2( double d ) { return Math.rint( d * 100 ) / 100.; } public static void main( String[] args ) { System.out.println( roundScale2(+1.341 ) ); // 1.34 System.out.println( roundScale2(–1.341 ) ); // –1.34 System.out.println( roundScale2(+1.345 ) ); // 1.34 System.out.println( roundScale2(–1.345 ) ); // –1.34 System.out.println( roundScale2(+1.347 ) ); // 1.35 System.out.println( roundScale2(–1.347 ) ); // –1.35 } }
Arbeiten wir anstatt mit rint() mit round(), wird die Zahl 1,345 nicht auf 1,34, sondern auf 1,35 gerundet. Wer nun Lust hat, etwas auszuprobieren, darf testen, wie der Formatstring »%.2f« bei printf() rundet.
5.4.5 Wurzel und Exponentialfunktionen 

Die Math-Klasse bietet weiterhin Funktionen zum Berechnen der Wurzel und weitere Exponentialfunktionen:
class java.lang.Math |
- static double sqrt( double x ) Liefert die Quadratwurzel von x; sqrt steht für square root.
- static double exp( double x ) Liefert den Exponentialwert von x zur Basis e (der Eulerschen Zahl e = 2,71828...) [Die irrationale Zahl e ist nach dem schweizerischen Mathematiker Leonhard Euler (1707 – 1783) benannt. ] , also ex.
- static double expm1( double x ) Liefert den Exponentialwert von x zur Basis e minus 1, also ex – 1. Berechnungen nahe null kann expm1(x) + 1 präziser ausdrücken als exp(x).
- static double pow( double x, double y ) Liefert den Wert der Potenz xy . Für ganzzahlige Werte gibt es keine eigene Funktion.
- static double cbrt( double a ) Berechnet die dritte Wurzel aus a.
5.4.6 Der Logarithmus 

Der Logarithmus ist die Umkehrfunktion der Exponentialfunktion. Die Exponentialfunktion und der Logarithmus hängen durch folgende Beziehung zusammen: Ist y = ax , dann ist x = loga(y). Der Logarithmus Math.log() ist der natürliche Logarithmus zur Basis e. In der Mathematik wird dieser mit »ln« angegeben (logarithmus naturalis). Logarithmen mit der Basis 10 heißen dekadische oder Brigg'sche Logarithmen und werden mit »lg« abgekürzt; der Logarithmus zur Basis 2 (binärer Logarithmus, dualer Logarithmus) wird mit »lb« abgekürzt. In Java gibt es die statische Funktion log10() für den Brigg'schen Logarithmus lg, nicht aber für den binären Logarithmus lb, der weiterhin nachgebildet werden muss. Allgemein gilt folgende Umrechnung: logb(x) = loga(x) / loga(b).
public static double lb( double x ) { return Math.log( x ) / Math.log( 2.0 ); } Da Math.log(2) konstant ist, sollte dieser Wert aus Performance-Gründen in einer Konstante gehalten werden. |
class java.lang.Math |
- static double log( double a ) Berechnet von a den Logarithmus zur Basis e.
- static double log10( double a ) Liefert von a den Logarithmus zur Basis 10.
- static double log1p( double x ) Liefert log(x) + 1.
5.4.7 Rest der ganzzahligen Division 

Neben dem Restwertoperator %, der den Rest der Division berechnet, gibt es auch eine Funktion IEEEremainder() in der Math-Klasse.
Listing 5.7 IEEEremainder.java
public class IEEEremainder { public static void main( String[] args ) { double a = 44.0; double b = 2.2; System.out.println( a / b ); // 20.0 System.out.println( a % b ); // 2.1999999999999966 System.out.println( Math.IEEEremainder( a, b ) ); // –3.552713678800501E-15 } }
Das zweite Ergebnis ist mit der mathematischen Ungenauigkeit fast 2,2, aber etwas kleiner, sodass der Algorithmus nicht noch einmal 2,2 abziehen konnte. Die Methode IEEEremainder() liefert ein Ergebnis nahe null (–0,0000000000000035527136788005), was besser ist, denn 44,0 lässt sich ohne Rest durch 2,2 teilen, also wäre der Rest eigentlich 0.
class java.lang.Math |
- static double IEEEremainder( double dividend, double divisor ) Liefert den Rest der Division von Dividend und Divisor (Modulo-Operator), so wie es der IEEE-754-Standard vorschreibt.
Eine Methode, die mitunter bessere Ergebnisse liefert (in unserem Fall wirklich 0,0) ist die folgende:
public static double remainder( double a, double b ) { return Math.signum(a) * (Math.abs(a) – Math.abs(b) * Math.floor(Math.abs(a)/Math.abs(b))); }
5.4.8 Zufallszahlen 

Positive Gleitkomma-Zufallszahlen zwischen größer gleich 0,0 und echt kleiner 1,0 liefert die Methode Math.random(). Die Rückgabe ist double und eine Typanpassung auf int führt immer zum Ergebnis 0.
Möchten wir Werte in einem anderen Wertebereich haben, ist es eine einfache Lösung, die Zufallszahlen von Math.random() durch Multiplikation auf den gewünschten Wertebereich auszudehnen und per Addition geeignet zu verschieben. Eine Zufallszahl zwischen x (inklusiv) und y (exklusiv) liefert Math.random() * (y – x) + x. Um ganzzahlige Zufallszahlen zwischen u und o (einschließlich) zu erhalten, berechnen wir u + Math.floor(Math.random() * (o-u+1)). Eine weitere einfache Lösung ist es, den Modulo-Operator einzusetzen und so den Wertebereich zu beschneiden. Noch besser ist allerdings der direkte Einsatz der Klasse Random und der Funktion nextInt(n), die das Kapitel später vorstellt.