1. Runden reeller Zahlen

Wie wir bereits besprochen haben, wird bei der Zuweisung einer reellen Zahl an eine intVariable diese immer auf die nächstkleinere Ganzzahl abgerundet – der Bruchteil wird einfach verworfen.

Aber man kann sich leicht eine Situation vorstellen, in der eine Bruchzahl in beide Richtungen auf die nächste ganze Zahl gerundet oder sogar aufgerundet werden muss. Was machen Sie in diesem Fall?

Für diese und viele ähnliche Situationen gibt es in Java die MathKlasse, die über die Methoden round(), ceil()und verfügt floor().


Math.round()Methode

Die Math.round()Methode rundet eine Zahl auf die nächste ganze Zahl:

long x = Math.round(real_number)

Aber hier gibt es noch eine weitere Nuance: Diese Methode gibt eine longGanzzahl zurück (kein int). Da reelle Zahlen sehr groß sein können, haben sich die Entwickler von Java entschieden, den größten verfügbaren Integer-Typ von Java zu verwenden: long.

Wenn ein Programmierer dementsprechend das Ergebnis einer intVariablen zuweisen möchte, muss er dem Compiler explizit mitteilen, dass er den möglichen Datenverlust akzeptiert (für den Fall, dass die resultierende Zahl nicht in einen intTyp passt).

int x = (int) Math.round(real_number)

Beispiele:

Stellungnahme Ergebnis
int x = (int) Math.round(4.1);
4
int x = (int) Math.round(4.5);
5
int x = (int) Math.round(4.9);
5

Math.ceil()Methode

Die Math.ceil()Methode rundet eine Zahl auf eine ganze Zahl auf. Hier sind Beispiele:

Stellungnahme Ergebnis
int x = (int) Math.ceil(4.1);
5
int x = (int) Math.ceil(4.5);
5
int x = (int) Math.ceil(4.9);
5

Math.floor()Methode

Die Math.floor()Methode rundet eine Zahl auf eine ganze Zahl ab . Hier sind Beispiele:

Stellungnahme Ergebnis
int x = (int) Math.floor(4.1);
4
int x = (int) Math.floor(4.5);
4
int x = (int) Math.floor(4.9);
4

Wenn Sie eine Zahl auf eine ganze Zahl abrunden, ist es natürlich einfacher, einfach einen Typumwandlungsoperator zu verwenden:(int)

Stellungnahme Ergebnis
int x = (int) 4.9
4

Wenn es Ihnen schwerfällt, sich diese Namen zu merken, hilft eine kurze Englischlektion:

  • Mathbedeutet Mathematik
  • Roundbedeutet rund
  • Ceilingbedeutet Decke
  • Floorbedeutet Boden

2. Wie Gleitkommazahlen aufgebaut sind

Der doubleTyp kann Werte im Bereich von bis speichern . Dieser große Wertebereich (im Vergleich zum Typ) erklärt sich aus der Tatsache, dass der Typ (wie auch ) eine völlig andere interne Struktur hat als Integer-Typen. Intern kodiert der Typ seinen Wert als zwei Zahlen: Die erste wird Mantisse und die zweite Exponent genannt .-1.7*10308+1.7*10308intdoublefloatdouble

Nehmen wir an, wir haben die Zahl 123456789und speichern sie als doubleVariable. Wenn wir das tun, wird die Zahl in konvertiert und der Typ speichert intern zwei Zahlen – und . Der Signifikand („signifikanter Teil der Zahl“ oder Mantisse) wird rot hervorgehoben, während der Exponent blau hervorgehoben wird.1.23456789*108double234567898

Dieser Ansatz ermöglicht die Speicherung sowohl sehr großer als auch sehr kleiner Zahlen. Da die Darstellung der Zahl jedoch auf 8 Bytes (64 Bit) begrenzt ist und einige der Bits zum Speichern des Exponenten (sowie des Vorzeichens der Mantisse und des Exponenten) verwendet werden, sind die maximal verfügbaren Ziffern zur Darstellung der Mantisse verfügbar ist 15 .

Dies ist eine sehr vereinfachte Beschreibung der Struktur reeller Zahlen.


3. Präzisionsverlust beim Arbeiten mit reellen Zahlen

Bedenken Sie bei der Arbeit mit reellen Zahlen immer, dass reelle Zahlen nicht exakt sind . Bei der Konvertierung von dezimal nach binär kann es immer zu Rundungs- und Konvertierungsfehlern kommen . Darüber hinaus ist die häufigste Fehlerquelle der Genauigkeitsverlust beim Addieren/Subtrahieren von Zahlen auf völlig unterschiedlichen Skalen.

Diese letzte Tatsache ist für unerfahrene Programmierer ein wenig überwältigend.

Wenn wir von subtrahieren , erhalten wir .1/109109109

Subtrahieren von Zahlen auf völlig unterschiedlichen Skalen Erläuterung
1000000000.000000000;
-         0.000000001;
 1000000000.000000000;
Die zweite Zahl ist extrem klein , was dazu führt, dass ihr Signifikand (grau hervorgehoben) ignoriert wird. Die 15 signifikanten Ziffern werden orange hervorgehoben.

Was können wir sagen, Programmieren ist nicht dasselbe wie Mathematik.


4. Fallstrick beim Vergleich reeller Zahlen

Eine weitere Gefahr lauert auf Programmierer, wenn sie reelle Zahlen vergleichen. Es entsteht bei der Arbeit mit reellen Zahlen, weil sich Rundungsfehler anhäufen können. Das Ergebnis ist, dass es Situationen gibt, in denen erwartet wird, dass die reellen Zahlen gleich sind, dies aber nicht der Fall ist. Oder umgekehrt: Es wird erwartet, dass die Zahlen unterschiedlich sind, aber sie sind gleich.

Beispiel:

Stellungnahme Erläuterung
double a = 1000000000.0;
double b = 0.000000001;
double c = a - b;
Der Wert der Variablen a beträgt 1000000000.0
Der Wert der Variablen c beträgt 1000000000.0
(die Zahl in der b Variablen ist zu klein)

Im obigen Beispiel sollten aund cnicht gleich sein, aber sie sind es.

Oder nehmen wir ein anderes Beispiel:

Stellungnahme Erläuterung
double a = 1.00000000000000001;
double b = 1.00000000000000002;
Der Wert der Variablen a wird sein. 1.0
Der Wert der Variablen b wird sein1.0

5. Eine interessante Tatsache überstrictfp

Java hat ein spezielles strictfpSchlüsselwort ( strict floating point ), das in anderen Programmiersprachen nicht zu finden ist . Und wissen Sie, warum Sie es brauchen? Es verschlechtert die Genauigkeit von Operationen mit Gleitkommazahlen. Hier ist die Geschichte, wie es dazu kam:

Java-Ersteller:
Wir möchten wirklich, dass Java sehr beliebt ist und dass Java-Programme auf möglichst vielen Geräten ausgeführt werden. Deshalb haben wir dafür gesorgt, dass die Spezifikation für die Java-Maschine besagt, dass alle Programme auf allen Gerätetypen gleich laufen müssen!
Hersteller von Intel-Prozessoren:
Hallo alle miteinander! Wir haben unsere Prozessoren verbessert und jetzt werden alle reellen Zahlen in unseren Prozessoren mit 10 Bytes statt mit 8 Bytes dargestellt. Mehr Bytes bedeuten mehr signifikante Ziffern. Was bedeutet das? Das ist richtig! Jetzt werden Ihre wissenschaftlichen Berechnungen noch genauer!
Wissenschaftler und alle, die an hochpräzisen Berechnungen beteiligt sind:
Cool! Gut gemacht. Hervorragende Nachrichten!
Java-Ersteller:
Nein, nein, nein, Leute! Wir haben Ihnen bereits gesagt, dass alle Java-Programme auf allen Geräten gleich laufen müssen . Wir werden die Möglichkeit, reelle 10-Byte-Zahlen in Intel-Prozessoren zu verwenden, zwangsweise deaktivieren.
Jetzt ist alles wieder gut! Danken Sie uns nicht.
Wissenschaftler und alle, die an hochpräzisen Berechnungen beteiligt sind:
Bist du völlig verrückt geworden? Schnell alles wieder so bekommen, wie es war!
Java-Ersteller:
Leute, das ist zu eurem Besten! Stellen Sie sich vor: Alle Java-Programme laufen auf allen Geräten gleich . Das ist so cool!
Wissenschaftler und alle, die an hochpräzisen Berechnungen beteiligt sind:
Nein. Es ist überhaupt nicht cool. Schnell alles wieder so machen, wie es war! Oder wissen Sie, wo wir Ihr Java ablegen?
Java-Ersteller:
Hmm. Warum hast du das nicht gleich gesagt? Natürlich legen wir es zurück.
Wir haben Ihre Fähigkeit wiederhergestellt, alle Funktionen der neuesten Prozessoren zu nutzen.
Übrigens... Wir haben das strictfpSchlüsselwort auch speziell zur Sprache hinzugefügt. Wenn Sie es vor den Namen einer Funktion schreiben, sind alle Operationen mit reellen Zahlen innerhalb dieser Funktion auf allen Geräten gleich schlecht !