# Großer Java bug beim rechnen?



## Bug? (7. Sep 2007)

Also entweder ich kann nicht mehr rechnen oder java kanns nicht 

hier mein code:

(testet vorher mal mit nem taschenrechner was rauskommt^^)

```
public class test4 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
	double lol ;
	lol=16.6;
	lol=lol+3.9;
	lol=lol+3.9;
	lol=lol+3.9;
	System.out.print(lol);
	

	}

}
```



Beim normalen Taschenrecher kommt 28,3 raus was ja auch richtig ist. nur das java progrmam zeigt mir ne Periodische Zahl an. Bug oder?


----------



## P3AC3MAK3R (7. Sep 2007)

Welche Zahl wird denn konkret ausgegeben?


----------



## Gast (7. Sep 2007)

wie meinst du das genau?
also bei einem "externen" taschen rechner kommt 28,3 raus ( kopf sagt das auch ^^)

aber bei dem programm kommt: 28.299999999999997 raus


----------



## Gast (7. Sep 2007)

also ganz periodisch ist das auch nicht ^^


----------



## Gast (7. Sep 2007)

also mir kommt das ganze ziemlich komisch vor.
zu genau rechnen geht eigentlich nicht. das muss eigentlich schon n java bug sein. ich hab das ganze grad mal in basic probiert. da rechnet der alles ohne fehler ( qbasic und vb.net)


----------



## Gast (7. Sep 2007)

ich hab grad noch typenumwandlung probiert. hilft auch nichts der bug bleibt bestehen


----------



## Gast (7. Sep 2007)

das interesannte ist dass wenn man die 3*3.9 zusammenfast auf 11,7 und das mit 16,6 addiert kommt das richtige ergebniss raus.

Das ist mal voll strange


----------



## Wildcard (7. Sep 2007)

Das ist kein Bug. So funktionieren Computer nunmal.
Lesen:
http://docs.sun.com/source/806-3568/ncg_goldberg.html


----------



## SlaterB (7. Sep 2007)

ein Computer hat Probleme, bestimmte Zahlen als Bits und Bytes darzustellen,
genau wie im Zehnersystem 1/3 = 0.333333 schwer darzustellen ist
das ist kein Bug, sondern ein generelles Problem von Computern,

natürlich ist es auch möglich, genau zu rechnen, wenn man nur genug Speicher bereitsstellt, BigDecimal z.B.,
double ist aber ein optimiertes kleines Format mit dem Nachteil der Ungenauigkeit


----------



## Marco13 (7. Sep 2007)

SlaterB hat gesagt.:
			
		

> natürlich ist es auch möglich, genau zu rechnen, wenn man nur genug Speicher bereitsstellt, BigDecimal z.B.,


Grundsätzlich widerspreche ich da jetzt nicht. Dass "genug Speicher" bei periodischen Zahlen (bzw. spätestens bei irrationalen Zahlen wie PI) gleichbedeutend ist mit "unendlich viel Speicher" macht das ganze aber etwas problematisch.

Ich persönlich finde BigDecimal übrigens extrem häßlich, und man sollte IMHO einen Anfänger nicht dazu verleiten, jeden Sch.... Kleinkram mit BigDecimal zu rechnen. Es gibt IMHO nur SEHR wenige sinnvolle Anwendungsgebiete für diese Klasse. (Im Moment fallen mir GARkeine ein... Und wenn jetzt irgendwas von "Finanzwesen" erzählt wird: Wer für sawas BigDecimal verwendet, ist selbst Schuld...)


----------



## SlaterB (7. Sep 2007)

ich bezog mich jetzt nur auf 16.6+3.9 usw.,
also alles was ein normaler Mensch im Zehnersystem rundungsfehlerfrei hinbekommt 

natürlich auch wiederum nicht mit 2 Mil. Nachkommastellen, so dass allein dadurch der Speicher gesprengt wird


----------



## ms (7. Sep 2007)

@Marco13
Was soll den deiner Meinung nach verwendet werden, wenn nicht BigDecimal?

Hier übrigens ein Beitrag, der die Problematik ein wenig erläutert.

ms


----------



## The_S (7. Sep 2007)

Marco13 hat gesagt.:
			
		

> Es gibt IMHO nur SEHR wenige sinnvolle Anwendungsgebiete für diese Klasse. (Im Moment fallen mir GARkeine ein... Und wenn jetzt irgendwas von "Finanzwesen" erzählt wird: Wer für sawas BigDecimal verwendet, ist selbst Schuld...)



Ich hab ma nen (wissenschaftlich angehauchten) Taschenrechner geschrieben, der auch mit etwas größeren Zahlen umgehen kann. Dafür habsch das z. B. gebraucht


----------



## Wildcard (7. Sep 2007)

Es ist kein Problem von Computern, sondern eine Besonderheit der verwendeten Zahlensysteme.
Es gibt auch Zahlen die sich im Dezimal System nicht mit endlichen Nachkommastellen abbilden lassen, in anderen Zahlensystemen aber sehr wohl.
Man denke nur an 1/3:
0,33333....x10
0,1x3
 :wink:


----------



## Gast (7. Sep 2007)

ui ist ja doch recht kompliziert ^^.gibs da jetzt nen einfachen zahlentyp der sicher ist? und wie muss ich den am code anwednden?


----------



## The_S (7. Sep 2007)

joa, alles, was keine Nachkommastellen hat, ist sicher! Bei nach kommastellen dann halt immer mal runden  .


----------



## ms (7. Sep 2007)

Entweder runden oder BigDecimal verwenden.
BigDecimal ist zwar nicht grad sehr handlich, wie Marco schon gesagt hat, dafür gibts aber keine Probleme.

ms


----------



## Wildcard (7. Sep 2007)

Was stört dich an den Ergebnissen? Oder anders, für was meinst du absolute Genauigkeit zu benötigen?


----------



## Gast (7. Sep 2007)

also wenn ich was mit einem computer rechne dann will ichs genau. sonst kann ich auch schätzen ^^


----------



## Gast (7. Sep 2007)

achso und noch ne frage zu BigDecimal wie genau geht das?

ich hab folgendes gemacht:

BigDecimal lol;

aber so gehts nicht?
wie genau muss ich BigDecimal anwenden?


----------



## Guest (7. Sep 2007)

mhh ich schreib doch lieber den code hier rien


```
import java.math.BigDecimal;



public class test4 {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
	BigDecimal lol ;
	lol=  16.6;
	lol=lol+ 3.9;
	lol=lol+  3.9;
	lol=lol+  3.9;
	System.out.print(String.valueOf(Math.round(lol)));
	

	}

}
```


----------



## Wildcard (7. Sep 2007)

Mit der Einstellung kommst du nicht weit.
Schnelle Berechnungen müssen auf vorhandenen Datentypen erfolgen und deren Einschränkungen sollte man kennen (siehe von mir geposteter Link).
Grundlos verwendet niemand andere Datentypen als float oder double, nur wenn es zwingend notwendig ist exakte Ergebnisse zu erhalten, oder mit sehr großen Zahlen umgehen muss, verwendet man Alternativen.


----------



## Gast (7. Sep 2007)

omg bahnhof ^^. ach man mir vergeht die lust an java . 
alles viel zu kompliziert und überal gibs ne ausnahme ^^.

Mag mir jemand mein code so verbessern dass es geht?


----------



## SlaterB (7. Sep 2007)

> wie genau muss ich BigDecimal anwenden?

Lehrbuch aufschlagen,
Lehrbuch lesen


----------



## Gast (7. Sep 2007)

ich will ja nix sagen ^^ aber mein buch :Grundkurs Programmieren in Java Band 1 beinhaltet keine BigDecimal 

steht wahrscheinlich in band 2


----------



## Saxony (7. Sep 2007)

Hiho,

man kann ja auch alle Zahlen vorher in das Sexagesimalsystem umwandeln.
Dieses wurde damals schon von den alten Babyloniern verwendet. Zudem besitzt es eine sehr gute Teilbarkeit.

Verwendet wird es selbst von uns noch -> Uhrzeit, da hiermit besser ("rundere") Zeitangaben möglich sind als mit dem Dezimalsystem.

Wird jeder sehen, wenn er seine Stundenerfassung immer in Dezimalform zurückbekommt.
Aha 8,08333 Stunden gearbeitet. Besser ist dann doch 8h5m 

Zusätzlich kommt dieses System auch noch in der Positionsbestimmung auf der Erde vor. Longitude und Latitude werden standardmäßig auch in Grad/Stunden°Minuten' und Sekunden" angegeben.

bye Saxony


----------



## Wildcard (7. Sep 2007)

Gast hat gesagt.:
			
		

> ich will ja nix sagen ^^ aber mein buch :Grundkurs Programmieren in Java Band 1 beinhaltet keine BigDecimal


Weil du es nicht brauchst und jetzt auch noch nicht verwenden möchtest.
Mit IEEE Zahlen musst du dich übrigens auch bei anderen Programmiersprachen beschäftigen...


----------



## The_S (7. Sep 2007)

Java programmieren ist eben nicht das selbe wie ne Fernbedienung zu programmieren. Java ist eine High-Level Sprache und deshalb von natur aus komplex, bietet dafür aber auch schon sehr viele Möglichkeiten, um die du dich nicht mehr selbst kümmern musst.

Wenn du keine Lust hast Java zu programmieren, dann lass es. Und wenn du es machen musst, dann bezahl jemanden dafür, dass er es für dich erleidgt. www.rentacoder.com


----------



## SlaterB (7. Sep 2007)

und falls dennoch ein Lehrbuch benötigt wird:
http://www.galileocomputing.de/openbook/javainsel6/javainsel_05_006.htm


----------



## Gast (7. Sep 2007)

äähm falsch ^^ ich werde bezahlt um mit java zu programmieren 

So und jetzt nochmal . Kann mir einer ne " gute " lösung mit quellcode geben?

IEEE hab ich auch noch nie gehört ^^


----------



## Gast (7. Sep 2007)

oh aber danke für den link. das scheint doch sehr verständlich geschrieben zu sein ^^


----------



## ms (7. Sep 2007)

BigDecimal ist eine Javaklasse und kein primitiver Datentyp. Findest also in der API.
http://java.sun.com/j2se/1.5.0/docs/api/java/math/BigDecimal.html
.

ms


----------



## Gast (7. Sep 2007)

mhh aber String schreib ich doch auch gros und das ist doch auch ein datenyp oder nicht?


----------



## The_S (7. Sep 2007)

ein String ist eine Klasse


----------



## Gast (7. Sep 2007)

omg jetzt raff ich blad gar nichts mehr.
Warum ist String ne klasse. ich dachte immer es sei ein Datentyp wie integer und double auch


----------



## Gast (7. Sep 2007)

also die sache ist eigentlich die. ich muss ein kleines verwaltunsprogramm schreiben dass buchungen zusammenzählen kann. das mit dem speichern usw hab ich schon hinbekommen. aber rwenn der "falsch" rechnet bringt mir das ja nix. 

Also was ist da jetzt gut geeignet dafür? das BigDecimal oder doch was anderes?


----------



## SlaterB (7. Sep 2007)

die Erde ist rund und String eine Klasse,
was du 'immer dachtest' ist kein Argument

-------

für die Buchungen könntest du auch int/ long verwenden und immer bedenken, dass die letzten beiden Ziffern die Nachkommastellen sind,
bei deinen allgemeinen Fähigkeiten steckt in jedem Verfahren aber Tücken, die dir zu schaffen machen werden


----------



## The_S (7. Sep 2007)

String hat Methoden, von daher ist String eine Klasse. Zwar eine besondere Klasse (siehe z. B. die Möglichkeit ohne new zu initialisieren), aber eine Klasse!


----------



## Saxony (7. Sep 2007)

Hiho,

nein String ist eine Klasse, die Java Syntax erlaubt aber mit String ähnlich zu Verfahren wie mit den primitiven Datentypen.


```
String s = "string";

// ist das selbe wie

String s = new String("string");
```

So und damit dein Porgramm auch 28,3 ausgibt mach folgendes:


```
public static void main(String[] args) {

		// TODO Auto-generated method stub
		double lol;
		lol = 16.6;
		lol = lol + 3.9;
		lol = lol + 3.9;
		lol = lol + 3.9;
		System.out.print(new DecimalFormat("#.##").format(lol));
	}
```

bye Saxony


----------



## The_S (7. Sep 2007)

Buchungen bestehen aus Geldbeträge und Geldbeträge haben idR 2 Nachkommastellen. Von daher nimmst du ein float und rundest immer mit Math.round auf zwei Stellen nach das Komma. Fertig!


----------



## Gast (7. Sep 2007)

ausnahmen über ausnahmen ^^.


----------



## ms (7. Sep 2007)

Man mag gar nicht glauben, wie toll eigentlich die java-doku ist.
http://java.sun.com/docs/books/tutorial/java/nutsandbolts/datatypes.html

ms


----------



## Guest (7. Sep 2007)

ok und das funktioniert immer? ok danke.

also im prinzip:


```
float lol;
l	lol=  16.6;
	lol=lol+ 3.9;
	lol=lol+  3.9;
	lol=lol+  3.9;
System.out.print(String.valueOf(Math.round(lol)));
```


aber wie genau rund ich da auf 2 stellen?


----------



## The_S (7. Sep 2007)

N String is ne Außnahme, die kannst du aber auch über new initialisieren. Vondaher keine Ausnahme, sondern es gibt eine Möglichkeit die Initialisierung zu "vereinfachen". IEEE ist auch keine Außnahme sondern eine Tatsache.

Also, wo siehst du jetzt Außnahmen über Außnahmen?


----------



## The_S (7. Sep 2007)

Auch du darfst die Forensuche verwenden. Dort findest du ca. 5367509 Beispiele, wie man auf 2 Nachkommastellen rundet  .


----------



## Gast (7. Sep 2007)

ach wenn wir doch eh schon miteineder reden hättest es auch ruhig hinschreiben können


----------



## Gast (7. Sep 2007)

aprop float.

( siehe code den ich vorher gepostet habe)

warum funktioniert das so nicht?

wenn ich "lol" zu float mache kann ich nicht mehr normal addieren!


----------



## ms (7. Sep 2007)

Du mußt die Werte explizit als float angeben. Also '3.9f'.

ms


----------



## The_S (7. Sep 2007)

Du regst mich was auf ...


```
float lol ;
		   lol=16.6F;
		   lol=lol+3.9F;
		   lol=lol+3.9F;
		   lol=lol+3.94564F;
		   System.out.println(lol);
		   System.out.print(Math.round(lol * 100) / 100F);
```

Un jetzt will ich nix mehr hören!


----------



## Gast (7. Sep 2007)

och jetzt wos grad gemütlich wird ^^.

aber trotzdem danke


----------



## Bug? (7. Sep 2007)

Also entweder ich kann nicht mehr rechnen oder java kanns nicht 

hier mein code:

(testet vorher mal mit nem taschenrechner was rauskommt^^)

```
public class test4 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
	double lol ;
	lol=16.6;
	lol=lol+3.9;
	lol=lol+3.9;
	lol=lol+3.9;
	System.out.print(lol);
	

	}

}
```



Beim normalen Taschenrecher kommt 28,3 raus was ja auch richtig ist. nur das java progrmam zeigt mir ne Periodische Zahl an. Bug oder?


----------



## sparrow (7. Sep 2007)

Gast hat gesagt.:
			
		

> äähm falsch ^^ ich werde bezahlt um mit java zu programmieren



... ohne Wort ....


----------



## Gast (7. Sep 2007)

achso ^^ du wolltest doch noch wissen was ich mit ausnhamen meine. 

nur zum bleistift dass hinter die 3,9 jetzt n F muss usw ^^, fällt wahrscheinlich einem der nut mit java schafft nicht auf.

Mir als alter basicer fällt es doch sehr schwer sich durch die unendlichen weiten des java zu wühlen .



( ui das hab ich aber schön gesagt ^^)


----------



## SlaterB (7. Sep 2007)

float ist eh ein Sonderding,
bleib bei double, dann kann das f weg (allerdings muss dann ein d dran , 
sonst wird manchmal int / int = int gerechnet und automatisch gerundet, 3 / 2 = 1)


----------



## Gast (7. Sep 2007)

okay dann bleib ich bei double 

danke


----------



## SlaterB (7. Sep 2007)

hoffentlich hast du noch gelesen was ich noch als Klammer raneditiert habe


----------



## The_S (7. Sep 2007)

Auch das hat seinen Sinn! Dadurch wird verhindert, dass du nicht versehentlich Daten verlierst. Angenommen du würdest eine Kommazahl zu einer Ganzzahl hinzuzählen, wäre ja die logische Konsequenz, dass die Kommazahl auch zur Ganzzahl wird und deshalb die Nachkommastellen verliert. Der Compiler macht dich somit darauf aufmerksam, dass es hier zu Datenverlust kommen könnte. Und da ein double mehr Nachkommastellen als ein float haben kann, kann es auch hier zu Datenverlust kommen.

Deshalb musst du in solchen Situationen explizit angeben, dass du auch wirklich diesen Datentyp meinst. Normalerweiße macht man das durch casten. Aber bei Float, Double und Long ist es mögliche eine Kurzform zu verwenden.

Macht also alles Sinn und ist keineswegs eine Ausnahme.


----------



## Saxony (7. Sep 2007)

Hiho,

zudem habe ich schon 2 Seiten weiter vorne eine Lösung zum runden auf zwei stellen geposted. 

Und meine Hinweise zum Sexagesimalsystem hat auch niemand beachtet.  :lol: 

bye Saxony


----------



## tfa (7. Sep 2007)

sparrow hat gesagt.:
			
		

> Gast hat gesagt.:
> 
> 
> 
> ...



Wahrscheinlich in Handy-Klingeltönen...


----------



## Marco13 (7. Sep 2007)

ms hat gesagt.:
			
		

> @Marco13
> Was soll den deiner Meinung nach verwendet werden, wenn nicht BigDecimal?
> 
> Hier übrigens ein Beitrag, der die Problematik ein wenig erläutert.
> ...



Die Problematik ist mir sehr bewußt. Aber die Antwort ist einfach: Für das, was 90% aller Programmier machen, und woraus 95% des Quellcodes besehen, reicht float oder double. Mir würden aus Ausnahmen nur Finanzinstitute einfallen (die allerdings wohl eher COBOL als Java verwenden, und solche Probleme vmtl. eher mit Binary Coded Digits lösen würden), oder heikle wissenschaftliche Berechnungen, die aber (wenn es nicht gerade nur um einen Taschenrechner geht) "oft" zeitrkitisch sind, und BigDecimal ist SO ineffizient, dass sich jeder, der sowas braucht, C++ verwenden oder sich dafür eine eigene Klasse schreiben oder sich zumindest auf andere (effizientere) Bibliotheken stützen würden.




			
				Saxony hat gesagt.:
			
		

> Hiho,
> 
> ```
> String s = "string";
> ...


Das ist nichtmal das gleiche :wink: Beim ersten wird ein String aus dem internen pool verwendet, beim zweiten wird explizit eine neue String-Instanz erstellt.


----------



## Saxony (7. Sep 2007)

Schon klar , nur für mich als Entwickler ergeben sich in der weiteren Verwendung von s keine Unterschiede.

Zudem sollte es auch nur zeigen, dass String somit eine Klasse ist, da man davon Instanzen mittels new erzeugen kann.

bye Saxony


----------



## ms (7. Sep 2007)

Ich habe in den letzten Projekten eigentlich immer BigDecimal verwendet einfach nur um dieser Problematik aus dem Weg zu gehen. Dabei ging es nichtmal um hochwissenschaftliche Berechnungen sondern um ganz simple Preisdaten und einfache Berechnungen.

Wenn schon nicht jeder Entwickler diese Problematik intus hat, wie soll man dass dann einem aus der Fachabteilung erklären warum 24.4 + 3.9 nicht wie erwartet 28.3, sondern 28.299999999999997 ist. Wenn man dann versucht das Problem zu erklären muss man zwangsläufig technisch werden. Und da steigt ein nicht-Techniker meistens aus. Eigentlich interessiert es ihn auch gar nicht. Darum ist es auch, wie ich finde, legitim, für jede sch... Berechnung BigDecimal zu verwenden. Das sind zumindest meine Erfahrungen.

ms


----------



## Wildcard (7. Sep 2007)

Wenn du so an die Sache rangehst, das du Zahlen zur Berechnung verwendest die um viele Faktoren langsamer sind und ein vielfaches an Speicher fressen, nur um zu vermeiden ein wenig denken zu müssen, braucht man sich nicht wundern wenn Java oft als langsam verschrien wird.


----------



## Saxony (7. Sep 2007)

Wildcard hat gesagt.:
			
		

> Wenn du so an die Sache rangehst, das du Zahlen zur Berechnung verwendest die um viele Faktoren langsamer sind und ein vielfaches an Speicher fressen, nur um zu vermeiden ein wenig denken zu müssen, braucht man sich nicht wundern wenn Java oft als langsam verschrien wird.



Richtig.

Und was spricht bitte gegen das Runden von primitiven Gleikommezahlen?

Vor allem im finanztechnischen Bereich reicht für die ANZEIGE meist eine Rundung auf 2-4 Nachkommastellen. Weil sich niemand in einer Tabelle solche Werte anguggen will: 2,45454545 EUR. 

Da reicht 2,45 für die Anzeige, aber halt intern nicht vergessen weiterhin mit 2,45454545 zu rechnen.

Wie schon mal in einem anderen Thread erwähnt, habe ich ja für die VersicherungskammerBayern an einer Gebäudeversicherungssoftware mitgearbeitet.
Dort war der Tarifrechner aber so komplex (im Pflichtenheft eine Berechnung, erklärt auf knapp 300 Seiten  ), das die Genauigkeit von double nicht mehr ausgereicht hat, da es am Ende zu Differenzen im 1/10 Cent Bereich kam. Hier war also die Verwendung von BigDecimal Pflicht.

bye Saxony


----------



## Tobias (7. Sep 2007)

Mh, das Problem hatte ich mit einer ganz simplen Preis-Addition in einem Online-Shop auch schon mal... Da habe ich auch mit double gearbeitet und nur für die Anzeige gerundet und am Ende hatte ich eine Differenz von einem Cent. Weiß die Details nicht mehr (bin schon lange raus aus der Firma), aber das war eine ziemliche Scheiße .
Ende vom Lied war: Keine Zeit, kein Budget - nimm BigDecimal und machs fertig ...

mpG
Tobias


----------



## Saxony (7. Sep 2007)

Hiho,

kann man eigentlich nicht auch nen long für vor dem Komma und einmal long für nach dem Komma nehmen ?

bye Saxony


----------



## SlaterB (7. Sep 2007)

oder nur ein long und immer berücksichtigen, dass die letzten beiden Ziffern nach dem Komma stehen,
also in ganzen Cents rechnen


----------



## ms (7. Sep 2007)

Wildcard hat gesagt.:
			
		

> Wenn du so an die Sache rangehst, das du Zahlen zur Berechnung verwendest die um viele Faktoren langsamer sind und ein vielfaches an Speicher fressen, nur um zu vermeiden ein wenig denken zu müssen, braucht man sich nicht wundern wenn Java oft als langsam verschrien wird.


In diesem Fall hat das niemanden interessiert.



			
				Tobias hat gesagt.:
			
		

> Ende vom Lied war: Keine Zeit, kein Budget - nimm BigDecimal und machs fertig ...


So wie es aussieht bin ich nicht der einzige dem es so geht.   

ms


----------

