Rechnefehler

Status
Nicht offen für weitere Antworten.
G

Guest

Gast
Hallo

etwas, was mir nicht einleuchtet.

Code:
System.out.println(3.8-3.6);

Wieso ist das Ergebnis. 0.19999999999999973
 
G

Guest

Gast
weil Computer mit floats manchmal Rechenfehler machen. Nimm BigDecimal
 
S

Schokotorte

Gast
Anonymous hat gesagt.:
weil Computer mit floats manchmal Rechenfehler machen. Nimm BigDecimal

BigDecimal ist auch keine Lösung:

Code:
import java.math.BigDecimal;

public class TestArrayList {

	public static void main(String[] args) {
		BigDecimal ersteZahl = new BigDecimal(1.6);
		BigDecimal zweiteZahl = new BigDecimal(1.4);
		System.out.println(ersteZahl.subtract(zweiteZahl));
	}

}

ergibt 0.200000000000000177635683940025046467781066894531250!
 

HoaX

Top Contributor
welchen popligen taschenrechner meinst du denn? poplig schließt ja den mitgelieferten von microsoft ja schonmal aus ...

evtl weil der nicht die passenden datentypen nimmt sondern selber rechnet?

um deine nächste frage vorweg zu nehmen: weil es bedeutend langsamer ist als mit den nativen datentypen direkt zu rechnen.
 

Wildcard

Top Contributor
Schokotorte hat gesagt.:
Aber warum kann dann jeder popelige Windows-Taschenrechner es besser?
Eine Programmiersprache ist nunmal keine Client Anwendung. Ein Programmierer sollte wissen wie eine CPU arbeitet und damit umzugehen lernen. Die Genauigkeit einer float, double Variable ist nunmal eine fixe Größe und wer damit rechnet muss ob der Eigenarten wissen.
 
S

SlaterB

Gast
der Fehler kommt hier aber nicht durch die Subtraktion, falls das jemand denkt, sondern duch den leider verbuggten Konstruktor für double:
Code:
public class Test {

	public static void main(String[] args) throws Exception {

		BigDecimal ersteZahl = new BigDecimal(1.6);
	      BigDecimal zweiteZahl = new BigDecimal(1.4);
	      System.out.println(ersteZahl); 
	      System.out.println(zweiteZahl); 
	      System.out.println(ersteZahl.subtract(zweiteZahl)); 
	}

}
->
1.600000000000000088817841970012523233890533447265625
1.399999999999999911182158029987476766109466552734375
0.200000000000000177635683940025046467781066894531250

-------

dagegen korrekt:

Code:
public class Test {

	public static void main(String[] args) throws Exception {

		BigDecimal ersteZahl = new BigDecimal("1.6"); // oder String.valueOf(double)
		BigDecimal zweiteZahl = new BigDecimal("1.4");
		System.out.println(ersteZahl);
		System.out.println(zweiteZahl);
		System.out.println(ersteZahl.subtract(zweiteZahl));
	}

}
-> 

1.6
1.4
0.2
 

Wildcard

Top Contributor
in der double Variable kann aber niemals 1.4 stehen, da kann die BigDecimal Implementierung doch nichts für.
Auch wenn die Klasse in der JRE ausgeliefert wird, kann sie doch nur mit Wasser kochen.
 
S

SlaterB

Gast
wie grad reineditiert:

warum wohl ist Double.toString(3.3) gleich "3.3" und nicht "3............"?
hier wird gerundet und bei BigDecimal nicht, das ist nicht konsistent..

alle Welt muss manuell double in String umwandeln, was verrückterweise problemlos geht, wo ist da die Logik?
wenn das nur dieser Konstruktor automatisch machen würde, wie aberwitzig viele Fehler das ersparen würde,
von Performance kann da keine Rede sein, BigDecimal ist soo langsam
 

Wildcard

Top Contributor
Der Konstruktor kann es nicht machen, weil er nur den double Wert bekommt und da steht keine 1.4 drin weil man keine 1.4 als double ablegen kann.
Den meterlangen Hinweis in der API-Doc nicht gelesen? :roll:

EDIT: ok, hab dich falsch verstanden. Du meinst echtes runden. Auch das ist aber nicht ungefährlich, weil BigDecimal eigentlich beliebige Genauigkeit garantiert und daher nicht einfach so runden dürfte (woher soll es wissen das gerundet werden muss?).
Anfreunden könnte ich mich mit einem zusätzlichen boolean round oder so.
 
S

SlaterB

Gast
Double.toString(3.3) hat auch kein Runden-boolean-Parameter

wenn man im Quellcode 3.3 schreibt,
meint man dann wohl tatsächlich 3.3 oder 3.29999999999999982236431605997495353221893310546875?

ich habe noch nie gehört, dass jemand 3.3 eintippt um dann genau diesen Wert zu erhalten,
warum nicht 3.29999999999999982236431605997495353221893310546875 direkt in den Quellcode schreiben?

besonders wenn man mal 3.29999999999999982236431605997495353255555555555555 braucht,
dann kann man ja kaum nach einer Zahl suchen die wie 3.3 aussieht und doch um im Bereich 10^-20 um ein paar Stellen genau abweicht,
das ist doch verrückt,

3.3 ist IMMER 3.3, und wenn man schon in BigDecimal alle Zeit der Welt hat korrekt zu arbeiten, warum dann nicht?
das hat auch nix mit runden zu tun, einfach einen Konstruktor

public BigDecimal(double d) {
this(Double.toString(d));
}

dass darüber nachgedacht wurde zeigt ja die API und die statische valueOf-Methode,
und ein BigDecimal exakt aus einem double ist sicher auch nicht das verkehrteste,
aber wieso nicht andersrum, den Konstruktor mit String und das exakte in einer statischen Methode versteckt?

wie oft braucht man wohl BigDecimal(double d) im Verhältnis zu den zahllosen Fehlern damit wie im diesen Thread oder im gesamten Internet?,
sehr unglücklich gelaufen
 

Wildcard

Top Contributor
Ach schau mal an, SUN hat sich ja schon darum gekümmert mit einer Rundungs-Strategie:
http://java.sun.com/javase/6/docs/api/java/math/BigDecimal.html#BigDecimal(double,%20java.math.MathContext)
Den anderen sollte man aber vielleicht wirklich deprecated machen.
 
Status
Nicht offen für weitere Antworten.

Oben