Datentypen Double Division ungenau

Diskutiere Double Division ungenau im Java Basics - Anfänger-Themen Bereich.
Y

yeTh7

Hallo!

Scheinbar ist die Division von double Werten nicht ganz genau. Siehe:

System.out.println(0.84/0.07); // Output: 11.999999999999998

Ich vermute das hängt mit der Natur der Fließkommadarstellung zusammen. Dennoch schafft das jeder Taschenrechner auch. Gibt es einen Weg ein exaktes Resultat in Java zu erhalten?

Danke euch im Voraus!
 
H

httpdigest

Taschenrechner rechnen mit einer höheren Präzision als die, die sie für die Ausgabe benutzen. Intern erzeugt der Taschenrechner also natürlich auch Ungenauigkeiten, allerdings sieht man die nicht, da vorher für die Ausgabe gerundet wird.
Ein exaktes Resultat kannst du mit `java.math.BigDecimal` und dessen Operationen hinbekommen.
 
J

JustNobody

Also bei so Fragen würde ich empfehlen, doch einmal selbst in Google zu suchen. Da findet sich dann ganz schnell ganz viel an Möglichkeiten.

Und ganz nebenbei übt man so, selbst Lösungen zu finden.


Aber ja, es gibt ganz viele Möglichkeiten. Einfach mal ein paar aufgezeigt:
Java:
import java.text.DecimalFormat;
import java.text.NumberFormat;

public class Test {
    public static void main(String[] args) {
        System.out.printf("%.4f", 0.84/0.07);
        System.out.println();
        System.out.format("%.4f", 0.84/0.07);
        System.out.println();

        NumberFormat formatter = new DecimalFormat("#0.0000");
        System.out.println(formatter.format(0.84/0.07));

        System.out.println(String.format("%.4f", 0.84/0.07));
    }
}
Und siehe da: Alle liefern ein tolles Ergebnis:
Code:
12,0000
12,0000
12,0000
12,0000
 
Y

yeTh7

Also bei so Fragen würde ich empfehlen, doch einmal selbst in Google zu suchen. Da findet sich dann ganz schnell ganz viel an Möglichkeiten.

Und ganz nebenbei übt man so, selbst Lösungen zu finden.
Hab schon selbst geschaut - meine Suchresultate waren aber entweder für meinen Fall unbrauchbar und unnötig komplex.

Für jemanden mit dem Wissen, ist es ein leichtes die Frage direkt zu beantworten. Recht herzlichen Dank! :)
 
J

JustNobody

Mein Hinweis mit dem Suchen war nicht böse gemeint. Bleib da immer dran! Mit der Zeit wirst Du auch immer schneller brauchbare Ergebnisse haben und wirst eine Ergebnisliste auch schneller nach möglicherweise hilfreichen Treffern durchsuchen können.

Daher würde ich Dir auch empfehlen, den Rat von Tobias aufzugreifen:
BigDecimal wird man nicht unbedingt brauchen - das habe ich etwas gezeigt. Aber da gibt es sehr interessante Methoden drin - die könnte man sich mal ansehen.

Ebenso könnte man sich die Dokumentation der Klassen, die ich verwendet habe, einmal ansehen (NumberFormat / DecimalFormat, String, ...)
 
Thallius

Thallius

Ich empfehle immer wieder einfach mit int zu rechnen wenn man keine Werte größer 10mio braucht. Schlich und effektiv
 
J

JustNobody

Aber wenn man das auf 4 Nachkommastellen haben will, dann wird es halt doch etwas komplexer.
Da wird dann einiges deutlich komplexer. So Komma-Verschiebungen kann man machen, aber ob sich das wirklich immer lohnt?
 
T

Tobias-nrw

Java:
double d1 = 0.84 / 0.07;
double d2 = Math.round(d1 * 10e5) / 10e5;
System.out.println(d2);
 
Thallius

Thallius

Genau das ist das Problem. Es ist eben nicht ganz so intuitiv und man muss mehr nachdenken. Sonst passieren so dumme Fehler.

Es ist eben 12 und nicht 0,12.
du Must also wirklich nachdenken um alle zahlen mit einem Faktor von 100 zu benutzen? Jetzt verstehe ich so langsam warum die heutige Software immer schlechter wird wenn ein Programmierer nich mal dazu in der Lage ist sowas Triviales voll automatisch im Kopf umzusetzen. Schreibt ihr für sowas Unit Tests?
 
mrBrown

mrBrown

du Must also wirklich nachdenken um alle zahlen mit einem Faktor von 100 zu benutzen?
Einer von euch beiden hat das falsche Ergebnis hingeschrieben - @JustNobody war es nicht.


Jetzt verstehe ich so langsam warum die heutige Software immer schlechter wird wenn ein Programmierer nich mal dazu in der Lage ist sowas Triviales voll automatisch im Kopf umzusetzen. Schreibt ihr für sowas Unit Tests?
So langsam verstehe ich, warum so viele Software so scheiße ist, wenn alle Programmierer meinen, sowas triviales im Kopf zu können und auf Unit-Tests zu verzichten.
 
L

LimDul

du Must also wirklich nachdenken um alle zahlen mit einem Faktor von 100 zu benutzen? Jetzt verstehe ich so langsam warum die heutige Software immer schlechter wird wenn ein Programmierer nich mal dazu in der Lage ist sowas Triviales voll automatisch im Kopf umzusetzen. Schreibt ihr für sowas Unit Tests?
Ich würde für sowas Unit-Tests erwarten. Denn hier interagieren gleich zwei Faktoren miteinander:
* Konvertierung eines double/float in Int. Wie verhält sich das bei 1,999? Wird da 200 oder 199 raus? Und bei 1,991? Und bei 1,995? Erfolgt die Umwandlung nach der Multiplikation durch cast oder Rundung? Und durch welchen Runderungsmodus?
* Dann die Integer-Division. Was kommt bei 15/8 raus? 1 oder 2?


Also für trivial halte diese Methode nicht - Im Gegenteil, ich halte sie für eine gefährliche Bastellösung. Entweder ich rechne mit double und akzeptiere die ungenauigkeit durch die Fließkommaarithmetik und Runde ggf. am Ende. Oder ich nehme gleich BigDecimal, wenn ich es genau brauche.
 
J

JustNobody

du Must also wirklich nachdenken um alle zahlen mit einem Faktor von 100 zu benutzen? Jetzt verstehe ich so langsam warum die heutige Software immer schlechter wird wenn ein Programmierer nich mal dazu in der Lage ist sowas Triviales voll automatisch im Kopf umzusetzen. Schreibt ihr für sowas Unit Tests?
Einfache Mathematik erläutert.

Du hast a / b = c. Die Division sehen wir jetzt einfach mal als Bruch und erweitern ihn mit 100.
a / b = a * 100 / b * 100 = c

Das Ergebnis ist also gleich. Wenn Du a und b beide mit 100 multiplizierst, dann hast Du immer noch das gleiche Ergebnis. Man muss das Ergebnis also nicht durch 100 teilen!

Anders bei a + b = c. Hier können wir dann beide Seiten mit 100 multiplizieren. Dann hast du 100 * (a+b) = 100 c = 100a + 100b = 100c.

Also Du musst sehr gut aufpassen, was du wie machst. Und wie Du schön gezeigt hast: Da können sich mal eben Fehler einschleichen. Da mag man gerne argumentieren, dass ein "Guter" (Programmierer schreibe ich mal nicht .... evtl. Mathematiker? Aber egal was ... jemand, der gut ist auf jeden Fall) das doch auf Anhieb sieht.
==> Ja das ist richtig. Das habe ich ja vielleicht gezeigt. Ich habe Deinen Text gelesen und es sofort gesehen.

Aber dann sind wir wieder beim Thema Clean Code. Was soll das? Ein Guter Entwickler/Programmierer kann auch schlechten Code lesen!
==> Es sollen aber auch weniger gute Entwickler lesen können und jeder, der es liest, soll es in möglichst kurzer Zeit lesen können. Und das auch noch möglichst Fehlerfrei.

Nehmen wir einfach Deinen Fall: Immer wenn ich das Lese, muss ich kurz drüber nachdenken: Ist das richtig? Das kostet Zeit. Egal wie gut ich bin.
==> Klar, das wird gekapselt in eine Library, ich habe Unit Tests u.s.w. Da wird es dann praktkabel. Also es geht nicht um das generelle "mit Integern arbeiten". Das kann in vielen Szenarien Sinn machen ...
 
J

JustNobody

Ich würde für sowas Unit-Tests erwarten. Denn hier interagieren gleich zwei Faktoren miteinander:
* Konvertierung eines double/float in Int. Wie verhält sich das bei 1,999? Wird da 200 oder 199 raus? Und bei 1,991? Und bei 1,995? Erfolgt die Umwandlung nach der Multiplikation durch cast oder Rundung? Und durch welchen Runderungsmodus?
* Dann die Integer-Division. Was kommt bei 15/8 raus? 1 oder 2?
Das muss man ja definieren. Ich habe eine definierte Genauigkeit und mit der Rechne ich dann. Und dann wird da auch vieles klar definiert.

Und ganz klar: Wenn ich nur eine Genauigkeit von 2 Stellen haben will, dann kann die Genauigkeit von double ausreichen.

Aber wenn ich dann plötzlich ganz ganz viele Additionen / Subtraktionen habe und es genau sein muss, dann will ich das nicht mehr akzeptieren.
Beispiel Geld:
wenn ich Dir 1.000.000 Mal 0.01 Cent gebe, dann willst Du am Ende wirklich die 10.000 Euro haben. Keine 9,999,99 Euro oder so. Daher macht es hier z.B. Sinn, ganz klar Integer zu nutzen. Euro-Beträge z.B. in Cent zu speichen ist da eine gute Lösung.

Spätestens bei Buchhaltungs-Software fliegt einem das sonst schnell um die Ohren. Da brauche ich keine 1.000.000 Additionen. Da Multipliziere ich ja mit 0,19 bzw. teile durch 1,19 und so .... Ich schreibe eine Rechnung über 75,13 und da kommen 19% Umsatzsteuer drauf : 14,2747 Euro? Da muss dann meine Software natürlich ganz klar 14,27 Euro verbuchen. Schreibe ich zwei Rechnungen, dann soll das natürlich 28,54 und nicht 28,55 sein.

Also es geht nicht darum, die Idee komplett abzulehnen oder so. Man muss nur den Anwendungsfall genau sehen. Was brauche ich aus welchem Grund?

Und wenn ich der großer Number Cruncher bin, dann will ich Integer Operationen, alleine schon weil ich dann plötzlich ein vielfaches an Operationen erledigt bekomme. Wenn ich einen der Top Großrechner für 1 Tag belege oder nur für wenige Stunden macht ja evtl. doch einen Unterschied und könnte Bestandteil der Anforderungen sein :)
 
Thema: 

Double Division ungenau

Passende Stellenanzeigen aus deiner Region:
Anzeige

Neue Themen

Anzeige

Anzeige
Oben