Archiv verlassen und diese Seite im Standarddesign anzeigen : [Java] - Double immer mit 2 Nachkommastellen ausgeben
Servus Jungs
Ich fange seit neustem wieder an, Java zu lernen, haben wir aktuell in unserem Kurs, von daher schadets nicht, wenn man zuhause bisschen übt :)
So, ich verzweifle grad daran, wie ich bitte eine double dazu zwinge, sie immer mit zwei nachkommastellen auszugeben.
Ich hab da ein kleines Programm geschrieben als Übung: Man gibt das Startkapital ein, dann den Zinssatz und schließlich die Laufzeit in jahren, berechnet und so wird das alles wunderbar und wird in der Konsole auch angezeigt. Runden tut es aber nicht so, wie ich will, wenn eine Zahl zum Beispiel 4,503 lautet, rundet es auf 4,5. Gleiches bei 4,03, da wird auf 4,0 gerundet. Ich will aber dass auf 4,50 gerundet wird bzw auf 4,00. Dies ist aber leider nicht so! Hat da jemand ne Idee wie man das macht.
Hier mal der Code:
import java.io.*;
public class Zinsrechnungen {
public static double runden (double d1)
{
double ergebnis = Math.round(d1*Math.pow(10d,2))/Math.pow(10d,2);
return ergebnis;
}
public static void main ( String[] args ) throws IOException
{
BufferedReader in = new BufferedReader(new InputStreamReader(System.in) );
//------Variablen-----------
double Startkapital;
double Zinssatz; //ohne Prozentzeichen
int Laufzeit;
double S2;
int aktuelleLaufzeit = 1;
double Einnahmen;
double Guthabenlastyear;
//--------------------------
//------Funktion für die Tastaureingabe---------------
System.out.println("Geben Sie ihr Startkapital ein (in €): ");
Startkapital = Double.parseDouble(in.readLine());
System.out.println("Geben Sie ihr Zinssatz ein (ohne %): ");
Zinssatz = Double.parseDouble(in.readLine());
System.out.println("Geben Sie ihre Laufzeit ein (in Jahre): ");
Laufzeit = Integer.parseInt(in.readLine());
//------------------------------------------------------
S2 = runden(Startkapital);
double aktuellesGuthaben = S2;
System.out.println("---------------------------------------");
System.out.println("Startkapital: \t" + S2 + "€");
System.out.println("Zinssatz: \t" + Zinssatz + "%");
System.out.println("Laufzeit: \t" + Laufzeit + " Jahre");
System.out.println("---------------------------------------");
System.out.println("Guthaben am Anfang: \t \t" + Startkapital + "€");
for (aktuelleLaufzeit = 1; aktuelleLaufzeit <= Laufzeit; aktuelleLaufzeit = aktuelleLaufzeit + 1)
{
Guthabenlastyear = aktuellesGuthaben;
aktuellesGuthaben=aktuellesGuthaben + aktuellesGuthaben*(Zinssatz/100);
aktuellesGuthaben=runden(aktuellesGuthaben);
Einnahmen = aktuellesGuthaben - Guthabenlastyear;
Einnahmen = runden(Einnahmen);
System.out.println ("Guthaben nach dem " + aktuelleLaufzeit + ". Jahr: \t" + aktuellesGuthaben + " € \t (+ " + Einnahmen + "€)");
}
}
}
Und hier der Text der in der Konsole dabei ausgegeben wird:
Geben Sie ihr Startkapital ein (in €):
2000000
Geben Sie ihr Zinssatz ein (ohne %):
2.5
Geben Sie ihre Laufzeit ein (in Jahre):
20
---------------------------------------
Startkapital: 2000000.0€
Zinssatz: 2.5%
Laufzeit: 20 Jahre
---------------------------------------
Guthaben am Anfang: 2000000.0€
Guthaben nach dem 1. Jahr: 2050000.0 € (+ 50000.0€)
Guthaben nach dem 2. Jahr: 2101250.0 € (+ 51250.0€)
Guthaben nach dem 3. Jahr: 2153781.25 € (+ 52531.25€)
Guthaben nach dem 4. Jahr: 2207625.78 € (+ 53844.53€)
Guthaben nach dem 5. Jahr: 2262816.42 € (+ 55190.64€)
Guthaben nach dem 6. Jahr: 2319386.83 € (+ 56570.41€)
Guthaben nach dem 7. Jahr: 2377371.5 € (+ 57984.67€)
Guthaben nach dem 8. Jahr: 2436805.79 € (+ 59434.29€)
Guthaben nach dem 9. Jahr: 2497725.93 € (+ 60920.14€)
Guthaben nach dem 10. Jahr: 2560169.08 € (+ 62443.15€)
Guthaben nach dem 11. Jahr: 2624173.31 € (+ 64004.23€)
Guthaben nach dem 12. Jahr: 2689777.64 € (+ 65604.33€)
Guthaben nach dem 13. Jahr: 2757022.08 € (+ 67244.44€)
Guthaben nach dem 14. Jahr: 2825947.63 € (+ 68925.55€)
Guthaben nach dem 15. Jahr: 2896596.32 € (+ 70648.69€)
Guthaben nach dem 16. Jahr: 2969011.23 € (+ 72414.91€)
Guthaben nach dem 17. Jahr: 3043236.51 € (+ 74225.28€)
Guthaben nach dem 18. Jahr: 3119317.42 € (+ 76080.91€)
Guthaben nach dem 19. Jahr: 3197300.36 € (+ 77982.94€)
Guthaben nach dem 20. Jahr: 3277232.87 € (+ 79932.51€)
Daepilin
24.10.2012, 14:23
-> http://www.javaprogrammingforums.com/java-programming-tutorials/297-how-format-double-value-2-decimal-places.html
Klappt nicht wirklich. :(
System.out.println ("Guthaben nach dem " + aktuelleLaufzeit + ". Jahr: \t" + d.format(aktuellesGuthaben) + " € \t (+ " + d.format(Einnahmen) + "€)");
Kommt jetzt halt statt . ein ,
aber sonst das gleiche Problem.
Auch wenn ich math.round bzw runden () entferne aus meinem Script, tut sich da nichts.
Problem ist halt, ich will das alles in einer Zeile haben, da gehts nicht einfach mit System.out.println(f.format(d)); :(
Lolomoloko
24.10.2012, 15:28
wie sieht dein format string aus?
wie sieht dein format string aus?
meinst du das?
DecimalFormat d = new DecimalFormat("#.##");
Lolomoloko
24.10.2012, 15:39
meinst du das?
DecimalFormat d = new DecimalFormat("#.##");
das ist aber nicht das was du wolltest, das schneidet die stellen ab wenn sie unnötig sind. ;)
also 2.00 → 2 usw.
zumindest machts das bei mir.
schau dir mal die anderen beispiele dort an.
Multithread
24.10.2012, 15:45
Das schöne am prgorammieren ist das man es sich eine funktion die man vermisst auch schnell selber schreiben kann:
string str=double;
return str.substring(0,str.indexof(',')+2);
:dnuhr:
Mal so ganz primitiv, ohne irgendwelche Fehler abzufangen und in pseudocode(wird so nicht gleich laufen)
Satans Krümelmonster
24.10.2012, 15:54
@Chrysalis: was macht dein code, wenn die zahl nur zwei nachkommastellen hat?
2,5 soll beispielsweise als 2,50 ausgegeben werden. das macht deine funktion nicht.
Lolomoloko
24.10.2012, 16:34
@Chrysalis: was macht dein code, wenn die zahl nur zwei nachkommastellen hat?
2,5 soll beispielsweise als 2,50 ausgegeben werden. das macht deine funktion nicht.
zudem ist das ein übler hack
Kellendil
24.10.2012, 23:35
So, habs mal schnell ausprobiert:
Das folgende geht 100%ig : ]
public static String format(double i)
{
DecimalFormat f = new DecimalFormat("#0.00");
double toFormat = ((double)Math.round(i*100))/100;
return f.format(toFormat);
}
Edit: Zahl die du runden willst/mitgeben eingeben, bekommst nen string mit der formatierten Zahl zurück.
Kannste dann so verwenden
double a = xyz;
System.out.println(format(a));
Oder man nutzt das gute alte printf (Für die reine 2-Nachkommastellen-Geschichte, Runden muss man natürlich trotzdem falls gewünscht):
System.out.printf("%.2f", 3.14159);
Ist deutlich kürzer und meiner Meinung nach auch übersichtlicher als alles sonst so vorgeschlagene.
Kellendil
25.10.2012, 23:05
Kann man mit printf auch Strings aus ner Funktion formatiert zurückgeben? Ich kenn mich mit System.xxx.bla nicht so wirklich aus.
Aber dann wäre es natürlich deutlich einfacher.
Das Hauptproblem ist aber immer noch das Runden, das ist bei mir auch sehr unelegant. Und was besonders komisch ist:
format() rundet Zahlen eigentlich selber schon automatisch auf die hinterste Stelle. mit einer Ausnahme:
DecimalFormat f = new DecimalFormat("0.00");
f.format(0.0017) //=> Ausgabe = 0.00
f.format(0.0082) //=> Ausgabe = 0.01
f.format(0.0057) //=> Ausgabe = 0.01
f.format(0.0050001) //=> Ausgabe = 0.01
//ABER:
f.format(0.005) //=> Ausgabe = 0.00
//WTF? wird 0.005 nicht eigentlich aufgerundet? Oder bin ich völlig bescheuert?
System (http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/System.html).out ist in Java ein PrintStream, der mit der Standard-Ausgabe verknüpft ist. Theoretisch kann man auch eigene PrintStream-Objekte nutzen, allerdings ist das wieder deutlich umständlicher. String.format müsste eigentlich dieselbe Funktionalität mit deutlich schlankerer Syntax bieten, falls man das Resultat als String weiterverarbeiten will.
Das Runden auf ½-Stellen lässt sich eigentlich recht einfach durch folgende Formel erreichen: round(input*2) / 2.0 - das Resultat kann man dann wieder mit printf oder String.format passend ausgeben.
Kellendil
25.10.2012, 23:49
Wieso auf halbe Stellen Runden? Ich meinte ganz normales auf ganze Stellen Runden, was mit DecimalFormat.format(input) funktionieren sollte, aber was beim Runden auf die 2. Nachkommastelle eben NUR exakt bei 0.005 nicht funktioniert, da dieses auf 0.00 ab statt auf 0.01 aufgerundet wird. Bei 0.005001 wird hingegen korrekt auf 0.01 aufgerundet.
Thoronador
25.10.2012, 23:53
//ABER:
f.format(0.005) //=> Ausgabe = 0.00
//WTF? wird 0.005 nicht eigentlich aufgerundet? Oder bin ich völlig bescheuert?
Entweder nutzt die format()-Funktion das sogenannte "Banker's Rounding" oder "Round To Even", wo bei einer 5 gefolgt von Nullen nicht stur aufgerundet sondern auf die nächste gerade Ziffer gerundet wird - das wäre hier also 0.00 statt 0.01, weil letzere ungerade ist. Oder aber, und das erscheint mir in dem Falle auch wahrscheinlich, dir spielt hier die Genauigkeit von einfachen Fließkommazahlen einen Streich. Der Wert 0,005 lässt sich mit 32-Bit-Fließkommazahlen nach dem Standard IEEE 754 nicht exakt darstellen, weshalb die interne Repräsentation einen leicht davon abweichenden Wert hat, z.B. 0,00499999988824 oder sowas in der Art. Da diese interne Darstellung noch unter 0,005 liegt, wird dabei auch folgerichtig auf 0,00 abgerundet.
0.005001 hat eine interne Darstellung, welche leicht über 0,005 liegt, daher erscheint dort beim Runden auch der erwartete Wert.
Kellendil
26.10.2012, 00:01
Achja, Fließkommazahlen Dezimal-Binär spielen einem immer wieder ganz schöne Streiche. Ein Hoch auf Ints/Longs : D
Das mit dem Rundungsfehler leuchtet ein. Danke : ]
Wir sollten schleunigst mal ein paar neue Zeichen erfinden und unser Standard-Zahlensystem auf Hexadezimal umstelln. Dann gäbs endlich Ruhe mit einigen solchen Problemen : ]
Lolomoloko
26.10.2012, 11:51
Wir sollten schleunigst mal ein paar neue Zeichen erfinden und unser Standard-Zahlensystem auf Hexadezimal umstelln. Dann gäbs endlich Ruhe mit einigen solchen Problemen : ]
warum?
die begründung interessiert mich jetzt wirklich.
Cheesecake
26.10.2012, 12:30
Oder aber, und das erscheint mir in dem Falle auch wahrscheinlich, dir spielt hier die Genauigkeit von einfachen Fließkommazahlen einen Streich. Der Wert 0,005 lässt sich mit 32-Bit-Fließkommazahlen nach dem Standard IEEE 754 nicht exakt darstellen, weshalb die interne Repräsentation einen leicht davon abweichenden Wert hat, z.B. 0,00499999988824 oder sowas in der Art. Da diese interne Darstellung noch unter 0,005 liegt, wird dabei auch folgerichtig auf 0,00 abgerundet.
Da es hier ursprünglich um Geld ging, sollte man das noch einmal besonders hervorheben. Bei normalen Rechnungen sind Fließkommazahlen trotz dieser Probleme in Ordnung, aber damit Geldbeträge zu speichern, ist meistens alles andere als sinnvoll. Dafür sollte man lieber die kleinste Geldeinheit nehmen und die Beträge als Ganzzahl (am besten verpackt in einer eigenen, netten Klasse) speichern.
Kellendil
26.10.2012, 16:39
warum?
die begründung interessiert mich jetzt wirklich.
Weil man hexadezimale Zahlen problemlos in binäre umrechnen kann und andersrum, ohne irgendwelche Perioden ect. in den Nachkommateil zu bekommen, wodurch man mit Fließkommazahlen dezimal nie genau rechnen kann. Immer 4 binäre Stellen entsprechen einer Hexadezimalen Stelle. Ein weiterer Vorteil wäre, dass Zahlen ein wenig kürzer wären als im Dezimalsystem.
Ich glaube du hast nicht ganz verstanden, warum das Problem überhaupt auftritt. Das wird man mit einer hexadezimalen Repräsentation nämlich auch nicht lösen können.
Kellendil
26.10.2012, 19:19
Dann erklär mir das mal : ]
Was ist dann also der Grund dafür, dass man 0.005 nicht exakt darstellen kann? Wenn nicht die binäre/hexadezimale Handhabung der Zahl?
Thoronador
26.10.2012, 20:00
Der Grund dafür, dass man 0,05 im Hexadezimalsystem nicht exakt darstellen kann, ist die Tatsache, dass sich 0,05 nicht als endliche Summe von ganzzahligen Vielfachen von ganzzahligen Potenzen von 16 darstellen lässt. Das gibt es bei jedem Stellensystem, egal mit welcher Basis, nur abhängig von der Basis bei verschiedenen Werten. (So lässt sich beispielsweise im Dezimalsystem das Ergebnis der Division 1/3 nicht mit endlich vielen Ziffern exakt darstellen.) Bei Fließkommazahlen geht es nicht einmal nur um die Endlichkeit, sondern darum, dass die Mantisse auf eine bestimmte Anzahl von Stellen beschränkt ist. Das müssten 23 bzw. 24 Stellen (im Binärsystem) bei den üblichen Fließkommazahlen einfacher Genauigkeit sein.
Das heißt:
Selbst in einem hexadezimalen System hat man das Problem, dass sich bestimmte Beträge nicht exakt darstellen lassen. Das Problem würde man erst dann "lösen", wenn die zulässigen Geldbeträge nur noch derart sind, dass sie sich im hexadezimalen System darstellen lassen. Erreichen könnte man das beispielsweise, indem man festlegt, dass ein Euro aus 16 (oder meinetwegen auch 256) Cents besteht. Dann wären fünf Cent nicht mehr 0,05 Euro, sondern 0,3125 bzw. 0,01953125 Euro, und beide Zahlen ließen sich problemlos im Hexadezimalsystem mit endlich vielen Stellen exakt darstellen.
Nur wirst du wohl kaum mal eben so alle anderen Leute überzeugen können, wegen dieses Problems eine derartige Währungsreform durchzuführen. :p
Kellendil
26.10.2012, 23:58
Erreichen könnte man das beispielsweise, indem man festlegt, dass ein Euro aus 16 (oder meinetwegen auch 256) Cents besteht.
Genau das meinste ich doch mit "Standard-Zahlensystem auf Hexadezimal umstelln". Das man eben im Alltag hexadezimal rechnet. Dann gäbe es nämlich keine solchen Probleme mehr.
Nur wirst du wohl kaum mal eben so alle anderen Leute überzeugen können, wegen dieses Problems eine derartige Währungsreform durchzuführen. :p
Nein. Aber sinnvoll wäre es meiner Meinung nach : ]
Ich glaube du hast nicht ganz verstanden, warum das Problem überhaupt auftritt. Das wird man mit einer hexadezimalen Repräsentation nämlich auch nicht lösen können.
Du hast mich falsch verstanden. Siehe oben. Wenn überall (Geld, Schulmathematik) zur Basis 16 gerechnet werden wäre, gäbe es keine 0.00510 mehr und auch das Problem nicht.
Lolomoloko
27.10.2012, 10:16
Genau das meinste ich doch mit "Standard-Zahlensystem auf Hexadezimal umstelln". Das man eben im Alltag hexadezimal rechnet. Dann gäbe es nämlich keine solchen Probleme mehr.
im alltag gibt es doch sowieso kein problem.
das problem kommt ja erst wenn ein rechner mit endlicher präzision auskommen muss, und das ist strukturell, da ändert eine wilde umstellung auf hexadezimal auch nichts,
wie sollte sie auch.
Nein. Aber sinnvoll wäre es meiner Meinung nach : ]
es wäre vorallem umständlich.
Du hast mich falsch verstanden. Siehe oben. Wenn überall (Geld, Schulmathematik) zur Basis 16 gerechnet werden wäre, gäbe es keine 0.00510 mehr und auch das Problem nicht.
genau, es gäbe sie nicht mehr da du sie nicht darstellen könntest.
effektiver gewinn -1.
Kellendil
27.10.2012, 13:56
im alltag gibt es doch sowieso kein problem.
das problem kommt ja erst wenn ein rechner mit endlicher präzision auskommen muss, und das ist strukturell, da ändert eine wilde umstellung auf hexadezimal auch nichts,
wie sollte sie auch.
es wäre vorallem umständlich.
genau, es gäbe sie nicht mehr da du sie nicht darstellen könntest.
effektiver gewinn -1.
Es gäbe sie nicht mehr, dafür halt andere Zahlen. Und solange man nicht multipliziert/dividiert würde es schon was bringen, nämlich z.B Fehler wie den mit der 0.005 verhindern. Dass der Aufwand einer UMSTELLUNG in keinem Verhältnis zum Nutzen steht, ist mir klar, und dass es umständlich wäre, auch. Aber ich fände eben aus obigem Grund die Benutzung hexadezimaler Zahlen im Alltag sinnvoller als die dezimaler (nicht die Umstellung, habe mich oben falsch ausgedrückt).
Delta 38
27.10.2012, 14:02
Es gäbe sie nicht mehr, dafür halt andere Zahlen. Und solange man nicht multipliziert/dividiert würde es schon was bringen, nämlich z.B Fehler wie den mit der 0.005 verhindern. Dass der Aufwand einer UMSTELLUNG in keinem Verhältnis zum Nutzen steht, ist mir klar, und dass es umständlich wäre, auch. Aber ich fände eben aus obigem Grund die Benutzung hexadezimaler Zahlen im Alltag sinnvoller als die dezimaler (nicht die Umstellung, habe mich oben falsch ausgedrückt).
Multiplikation und Division sind aber nunmal Bestandteil des Alltags. Und warum sollte ein Zahlensystem zur Basis 16 besser für den Alltag geeignet sein? Man hat ja schließlich auch nur 10 Finger ;)
Um solche Sachen wie die Darstellung von Dezimalzahlen auf dem Computer kümmert sich der allgemeine Alltag nunmal nicht. Außerdem wurde vorhin ja schon gesagt: Mach eine Klasse Geld oder so daraus und als Membervariablen nimmst du dann Cent und Euro. Schon hast du das Problem auch nicht mehr ;)
Kellendil
27.10.2012, 16:49
Multiplikation und Division sind aber nunmal Bestandteil des Alltags. Und warum sollte ein Zahlensystem zur Basis 16 besser für den Alltag geeignet sein? Man hat ja schließlich auch nur 10 Finger ;)
Um solche Sachen wie die Darstellung von Dezimalzahlen auf dem Computer kümmert sich der allgemeine Alltag nunmal nicht. Außerdem wurde vorhin ja schon gesagt: Mach eine Klasse Geld oder so daraus und als Membervariablen nimmst du dann Cent und Euro. Schon hast du das Problem auch nicht mehr ;)
Wer weiß wie lange wir noch 10 Finger haben? Gentechnik schreitet voran : D
Wenn wir 16 haben, dann hol ich diesen Thread wieder aus der Versenkung : D
Time2Die
28.10.2012, 02:56
Oder man nutzt das gute alte printf (Für die reine 2-Nachkommastellen-Geschichte, Runden muss man natürlich trotzdem falls gewünscht):
System.out.printf("%.2f", 3.14159);
Ist deutlich kürzer und meiner Meinung nach auch übersichtlicher als alles sonst so vorgeschlagene.
Kann man das System.out.printf irgendwie auch mit Zeilenumbrüchen und Strings kombinieren?
Weil somit muss ich das nämlich in mehrere Zeilen schreiben (ein beispiel von mir):
System.out.print("Value of share: ");
System.out.printf("%.2f", value_of_share);
System.out.print("Commission rate: " + commission_rate);
System.out.print("\n");
System.out.print("Value of share: ");
System.out.printf("%.2f", value_of_share);
System.out.print("\n");
System.out.print("\n");
System.out.print("Commission: ");
System.out.printf("%.2f", commission);
System.out.print("\n");
Und ich will nicht Math.round verwenden, weil ich die Kommazahlen IMMER mit zwei Dezimalstellen ausgeben will, und bei Math.round ist es so, dass 3.499 nicht auf 3.40 gerundet wird, sondern auf 3.4.
Außerdem arbeite ich mit Geany und der cmd-Konsole (mehr sollten wir für unseren Unterricht auch zurzeit nicht brauchen) deshalb kann ich das mit den Zeilenumbrüchen nicht webbasiert umgehen.
UND GANZ wichtig: Gibt es denn einen einfach und kurzen Befehl, mit der ich ermitteln kann, welchen Datentyp eine Variable hat? Ich weiß, es erscheint dumm da ich ohnehin den Datentyp selbst definiere aber ich würde bei einem Beispiel gerne was einbauen à la
if(x!double)
{
irgend ein Befehl;
}
else
{
irgend ein anderer Befehl;
}
Gibt es so etwas? Ich suche schon so eifrig danach. :mad:
Delta 38
28.10.2012, 04:30
Benutze für den Zeilenumbruch das Escapezeichen '\n'. Für die bestimmung von Standart-Datentypen gibt es glaube ich kein Befehl (sonst such mal nach typeof oder so etwas in der Art). Was gehen würde wäre die größe mit sizeof zu vergleichen. Das funktioniert aber nicht durch alle Datentypen hindurch sondern nur, wenn bestimmte Typen unterschieden werden sollen. Ansonsten mach dir eine Wrapper-Klasse mit einem entsprechenden Vergleichsattribut.
EDIT: Ich seh gerade, dass es doch um Java und nicht C++ ging. Da hab ich wohl was verwechselt. Nichtsdestotrotz lassen sich die Standart (Primitive-) Datentypen nicht überprüfen.
Kellendil
28.10.2012, 11:56
Du kannst nur überprüfen, ob Objekte Instanzen einer Klasse sind, d.h. du könntest Integer-Objekte prüfen (mit "instanceof"), aber keine primitiven Datentypen.
Möglich wäre:
Integer a = 5;
if (a instanceof Integer)/**Do something*/;
Powered by vBulletin® Version 4.2.2 Copyright ©2025 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.