Ich habe also einen doppelten Satz auf 1234, ich möchte eine Dezimalstelle verschieben, um 12,34 zu erhalten
Um dies zu tun, multipliziere ich .1 bis 1234 zweimal, irgendwie so
double x = 1234;
for(int i=1;i<=2;i++)
{
x = x*.1;
}
System.out.println(x);
Dadurch wird das Ergebnis "12.340000000000002" gedruckt.
Gibt es eine Möglichkeit, den Double Store 12.34 korrekt zu formatieren, ohne ihn einfach auf zwei Dezimalstellen zu formatieren?
x /= 100;
?Antworten:
Wenn Sie
double
oder verwendenfloat
, sollten Sie Rundungen verwenden oder erwarten, dass Rundungsfehler auftreten. Wenn Sie dies nicht tun können, verwenden SieBigDecimal
.Das Problem, das Sie haben, ist, dass 0.1 keine exakte Darstellung ist. Wenn Sie die Berechnung zweimal durchführen, verschärfen Sie diesen Fehler.
100 können jedoch genau dargestellt werden. Versuchen Sie also:
welche druckt:
Dies funktioniert, weil
Double.toString(d)
in Ihrem Namen eine kleine Rundung durchgeführt wird, aber es ist nicht viel. Wenn Sie sich fragen, wie es ohne Rundung aussehen könnte:Drucke:
Kurz gesagt, eine Rundung ist für sinnvolle Antworten im Gleitkomma unvermeidlich, unabhängig davon, ob Sie dies explizit tun oder nicht.
Hinweis:
x / 100
undx * 0.01
sind nicht genau gleich, wenn es um Rundungsfehler geht. Dies liegt daran, dass der Rundungsfehler für den ersten Ausdruck von den Werten von x abhängt, während der0.01
im zweiten Ausdruck einen festen Rundungsfehler aufweist.druckt
quelle
1234/100
, wie Sie es getan haben, nichts mit dem zugrunde liegenden Problem zu tun - es sollte genau dem Schreiben entsprechen1234 * 0.01
./100
und*0.01
sind einander äquivalent, aber nicht den OPs*0.1*0.1
.Nein - Wenn Sie Dezimalwerte genau speichern möchten, verwenden Sie
BigDecimal
. kann eine Zahl wie 0,1double
einfach nicht genau darstellen, genauso wenig wie Sie den Wert eines Drittels genau mit einer endlichen Anzahl von Dezimalstellen schreiben können.quelle
Wenn es nur um die Formatierung geht, versuchen Sie es mit printf
Ausgabe
quelle
System.out.printf()
ist der richtige Weg.In Finanzsoftware werden häufig ganze Zahlen für Pennies verwendet. In der Schule wurde uns beigebracht, wie man Festkomma anstelle von Schweben verwendet, aber das sind normalerweise Zweierpotenzen. Das Speichern von Pennys in ganzen Zahlen kann auch als "Fixpunkt" bezeichnet werden.
Im Unterricht wurden wir allgemein gefragt, welche Zahlen in einer Basis genau dargestellt werden können.
Für
base=p1^n1*p2^n2
... können Sie jedes N darstellen, wobei N = n * p1 ^ m1 * p2 ^ m2.Lassen
base=14=2^1*7^1
Sie ... Sie können 1/7 1/14 1/28 1/49 aber nicht 1/3 darstellenIch kenne mich mit Finanzsoftware aus - ich habe die Finanzberichte von Ticketmaster von VAX asm in PASCAL konvertiert. Sie hatten ihr eigenes Format () mit Codes für Pennys. Der Grund für die Konvertierung war, dass 32-Bit-Ganzzahlen nicht mehr ausreichten. +/- 2 Milliarden Pennies sind 20 Millionen Dollar und das ist für die Weltmeisterschaft oder die Olympischen Spiele übergelaufen, habe ich vergessen.
Ich wurde zur Geheimhaltung verpflichtet. Naja. Wenn es in der Wissenschaft gut ist, veröffentlichen Sie; In der Industrie hält man es geheim.
quelle
Sie können die Darstellung von Ganzzahlen versuchen
quelle
r
kleiner als 10 ist, tritt keine 0-Auffüllung auf und 1204 würde ein Ergebnis von 12,4 ergeben. Die korrekte Formatierungszeichenfolge ähnelt eher "% d.% 02d"Dies wird durch die Art und Weise verursacht, wie Computer Gleitkommazahlen speichern. Sie machen das nicht genau. Als Programmierer sollten Sie diesen Gleitkomma-Leitfaden lesen , um sich mit den Schwierigkeiten beim Umgang mit Gleitkommazahlen vertraut zu machen.
quelle
Witzig, dass in zahlreichen Posts die Verwendung von BigDecimal erwähnt wird, aber niemand stört, um die richtige Antwort basierend auf BigDecimal zu geben? Denn auch mit BigDecimal können Sie Fehler machen, wie dieser Code zeigt
Gibt diese Ausgabe
Der BigDecimal-Konstruktor erwähnt ausdrücklich, dass es besser ist, den String-Konstruktor als einen numerischen Konstruktor zu verwenden. Die ultimative Präzision wird auch durch den optionalen MathContext beeinflusst.
Laut BigDecimal Javadoc ist es möglich , ein BigDecimal zu erstellen, das genau gleich 0,1 ist, vorausgesetzt, Sie verwenden den String-Konstruktor.
quelle
Ja da ist. Mit jeder Doppeloperation können Sie an Genauigkeit verlieren, aber die Genauigkeit ist für jede Operation unterschiedlich und kann durch Auswahl der richtigen Abfolge von Operationen minimiert werden. Wenn Sie beispielsweise einen Satz von Zahlen multiplizieren, ist es am besten, den Satz vor dem Multiplizieren nach Exponenten zu sortieren.
Jedes anständige Buch über das Knacken von Zahlen beschreibt dies. Zum Beispiel: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
Und um Ihre Frage zu beantworten:
Verwenden Sie dividieren statt multiplizieren. Auf diese Weise erhalten Sie das richtige Ergebnis.
quelle
Nein, da Java-Gleitkommatypen (in der Tat alle Gleitkommatypen) einen Kompromiss zwischen Größe und Genauigkeit darstellen. Während sie für viele Aufgaben sehr nützlich sind, sollten Sie sie verwenden, wenn Sie willkürliche Präzision benötigen
BigDecimal
.quelle