Java double ungenau?

Ich weiß Namen sind nicht gut gewählt - (Computer, programmieren, Java)

3 Antworten

Gleitkommaoperationen werden nur mit einer endlichen Genauigkeit, der so genannten Maschinengenauigkeit, durchgeführt.

Bei double precision Gleitkommazahlen nach IEEE 754 (der heutzutage von quasi allen Prozessoren umgesetzt wird) beträgt sie 2^(-53) = ~1.1 * 10^(-16).

Das ist der relative Fehler, der bei jeder einzelnen Gleitkommaoperation passiert.

Wenn Deine Zahl selbst bereits größer, als 10^16 ist, ist der absolute Fehler bereits größer, als eins.

Wenn Du höhere Präzision benötigst, gibt es in Java die Datentypen java.math.BigDecimal (für Gleitkommazahlen), sowie java.math.BigInteger (für Ganzzahlen). Diese sind aber etwas umständlicher zu verwenden und Operationen sind natürlich viel langsamer, als mit den elementaren Datentypen, da sie in mehreren Schritten in Software berechnet werden, während die nativen Datentypen bestenfalls in exakt einer Maschinenoperation verarbeitet werden können.

Richtig, double ist ungenau, da der Rechner die Zahlen nur anders speichern kann (binäre Darstellung eines Bruchs und eines Exponenten).

Wenn du genaue Werte brauchst, musst du BigDecimal nehmen.

Hier mehr: https://stackoverflow.com/questions/322749/retain-precision-with-double-in-java

Woher ich das weiß:Studium / Ausbildung – Studium Informatik und Hobby seit einigen Jahren

IQBaestie 
Beitragsersteller
 15.11.2017, 22:57

Wie genau implementier ich die BigDecimal? Ich komm da nicht drauf.

1
bormolino  15.11.2017, 22:58
@IQBaestie

Moment, ich schreibe mal einen BigDecimal-Code zu deinem Beispiel oben.

2
bormolino  15.11.2017, 23:11
@bormolino
import java.math.BigDecimal;

public class Test {
public static void main(String[] args) {

BigDecimal prothNumber = new BigDecimal("21181");
BigDecimal one = new BigDecimal("1");
BigDecimal two = new BigDecimal("2");
BigDecimal eight = new BigDecimal("8");
BigDecimal forty = new BigDecimal("40");

BigDecimal solution = prothNumber.multiply(two.pow(forty.intValue()).add(one));
BigDecimal solutionplus1 = solution.add(one);
BigDecimal solutionplus8 = solution.add(eight);

System.out.println(solution.toString());
System.out.println(solutionplus1.toString());
System.out.println(solutionplus8.toString());
}
}
4
IQBaestie 
Beitragsersteller
 15.11.2017, 23:34
@bormolino

Wow, ok das sieht ein bisschen kompliziert aus, aber danke dafür, sehr hilfreich.

1
IQBaestie 
Beitragsersteller
 15.11.2017, 22:51

Ich dachte double wird erst bei kleinen Kommazahlen ungenau, aber nicht im normalen Zahlenbereich von 0 bis 2^63.

1

Das hängt mit der Zahlendarstellung zusammen. Double hat 15.9 signifikante Stellen. Da 10^16 bereits 17 Stellen aufweist, werden kleine Zahlen "verschluckt". Es stehen einfach nicht genügend bits zur Verfügung, alle Stellen genau abzuspeichern.