das was du machen möchtest, lässt sich nativ mit BigDecimal#setScale(int, RoundingMode) realisieren. Allerdings gibst du dabei nicht 0.01, sondern 2 als scale an.
Gibt es einen Grund, weshalb du selbst rumrechnen möchtest?
Wenn es nur darum geht, die gegebene Zahl in einen „schönen“ String zu verwandeln, dann ist BigDecimal der falsche Weg. Das ist eine höchst-komplexe Klasse für mathematische Dinge, die man sehr selten braucht - und wenn sowas triviales wie eine Zahl auszugeben so ein komplexes Ding erfordern würde, wäre was falsch gelaufen.
Ganz trivial ist es aber tatsächlich nicht.
Die Anforderung, dass die „precision“ in der angedeuteten Form angegeben wird, ist … ja, blöd. Das kann man wohl so sagen. Aus „irgendeiner Zahl“ irgendeine sinnvolle Formatierungsregel abzuleiten führt fast zwangsläufig zu irgendwelchen Krämpfen: Was passiert bei precision=100, oder precision=-123, oder precision=-0.01, oder precision=0.09983, oder precision=Float.NaN? Das ergibt alles keinen Sinn. (Wer auch immer für diese Vorgabe verantwortlich ist: Sag’ ihm, dass das keinen Sinn ergibt!).
Besser wäre es, wenn direkt die Anzahl der gewünschten Nachkommastellen angegeben werden könnte.
Aber wenn es denn sein muss:
Ja, das ist das Zauberwort. Mit dem log10 kann man ausrechnen, wie viele Nachkommastellen die precision „0.01“ denn haben soll. (Das muss man dann noch runden - eigentlich immer _auf_runden, aber … wegen floating-point-Ungenauigkeiten ist’s hier ein round…).
10.137559 formatted with precision 10.0 is 10
10.137559 formatted with precision 1.0 is 10
10.137559 formatted with precision 0.1 is 10.1
10.137559 formatted with precision 0.01 is 10.14
10.137559 formatted with precision 0.001 is 10.138
10.137559 formatted with precision 1.0E-4 is 10.1376
10.137559 formatted with precision 1.0E-5 is 10.13756
10.137559 formatted with precision 1.0E-6 is 10.137559
10.137559 formatted with precision 1.0E-7 is 10.1375589
amount und precision habe ich geändert in double. Math.floor( ) will leider double haben und gibt auch nur double zurück. D. h., wenn man mit float rechnet, dann entstehen diese Rundungsfehler.
Es geht sicherlich auch besser, aber precision wird nun mal so von der Exchange vorgegeben. float und double beißen sich leider etwas, bzw., die gesamten Math-Funktionen sind für double konzipiert worden; dass aber bei der Umwandlung von double nach float Ungenauigkeiten auftreten, wurde nicht bedacht.
Sowohl bei double als auch bei float entstehen unter bestimmten Bedingungen Fehler. Es sind so gesehen auch die gleichen Fehler, sie sind nur unterschiedlich groß.
(Nebenbei: Wenn es um dieses Thema geht, neigen einige Schlauköpfe dazu, auf What Every Computer Scientist Should Know About Floating-Point Arithmetic zu verweisen, aber … falls jemand behaupten will, das von Anfang bis Ende gelesen zu haben, möge er sich bei mir melden. Und falls jemand behaupten will, das alles nachvollzogen und verstanden zu haben: Ja, du Nerd, und, wie formatiert man jetzt so einen albernen String? Man kann da unterschiedlichSTe Prioritäten setzen…)
Du redest jetzt von „funktionieren“, erwähnst nebenbei sowas wie amount mal price <= sum (und keiner weiß, was „amount“ in dem Fall ist), und stellst zu Recht die Frage, was es mit dieser 1e+5 auf sich hat, aber die übergeordnete Frage ist: Was heißt „funktionieren“? Hast du eine Spezifikation? Sagt die, was bei precision=-0.123 passieren soll?
Was auch immer du da für clevere Formatierungsregeln austüftelst: Wenn dann jemand kommt, und das mit formatAmount(1234, 0.000000234, -100.666) aufruft, wird irgendwas „nicht funktionieren“.
(Es könnte sein, dass die Regeln so abstrus sind, dass man das ganze wirklich am „einfachsten und sichersten“ auf Basis von Strings formatiert. Aber bevor man auf solche verzweifelten Lösungen zurückgreift, sollte man sicher sein, dass es nichts „besseres“ gibt…)
funktioniert == erfüllt die Anforderung (für die meisten Fälle)
funktioniert nicht == erfüllt nicht die Anforderung (für die meisten Fälle)
ich dachte, das sei nicht so schwer zu verstehen…
amount ist der Rückgabewert der Methode (das, was sie zurückgibt). precision kann nur 1.0, 0.1, 0.01, usw. sein. Und es ist 1e-5, nicht 1e+5 … ein kleiner, aber feiner Unterschied …
Für amount==Rückgabe der Methode==quantity muss also gelten: (quantity-precision)%precision==0 (<-- da steht 0! NICHT irgendetwas nahe 0…)
Wenns gar nicht anders geht, nehm ich halt long… Die 32 oberen Bit die Vorkommastellen und die 32 unteren Bit die Nachkommastellen. Müsste doch klappen?