0.7+0.2

Status
Nicht offen für weitere Antworten.
G

Guest

Gast
hi mal ne frage :
wieso kommt wenn ich in einen java programm 0.7+0.2 rechne 0.8999999999999999 raus?
was kann ich unternehmen damit ich das korrekte ergebnis erhalte ?
 
R

Roar

Gast
runden
btw: es gibt einige threads zu dem thema wo das ausführlicher erläutert wird: suchfunktion
 

Illuvatar

Top Contributor
Hm da hab ich aber mal nen Test gemacht (hab ich den eigentlich schonmal gepostet? kA):

Java

Code:
public class FloatingPointTest
{
	public static void main (String[] args)
    {
    	for (double d = 0; d < 5; d += .2){
    		System.out.println (d);
    	}
    }
}
0.0
0.2
0.4
0.6000000000000001
0.8
1.0
1.2
1.4
1.5999999999999999
1.7999999999999998
1.9999999999999998
2.1999999999999997
2.4
2.6
2.8000000000000003
3.0000000000000004
3.2000000000000006
3.400000000000001
3.600000000000001
3.800000000000001
4.000000000000001
4.200000000000001
4.400000000000001
4.600000000000001
4.800000000000002

C#

Code:
using System;

namespace MyTest
{
	public class FloatingPointTest
	{
		public static void Main (string[] args)
		{
			for (double d = 0; d < 5; d += .2){
				Console.Out.WriteLine (d);
			}
		}
	}
}
0
0,2
0,4
0,6
0,8
1
1,2
1,4
1,6
1,8
2
2,2
2,4
2,6
2,8
3
3,2
3,4
3,6
3,8
4
4,2
4,4
4,6
4,8
 
B

Beni

Gast
Ich könnte mir gut vorstellen, dass die C#-Print-Methode noch ein bisschen rundet.

Wildcard hat schon recht, die Fliesskommazahlen können einige "einfache" Dezimalzahlen schlicht nicht darstellen.
 
R

Roar

Gast
ja weil c, c# etc. automatisch runden oder so.

edit: mist 1 sekunde später
 
G

Guest

Gast
Nöö, es ist sicherlich eine andere interne Darstellung von Dezimalzahlen.
Es gibt Sprachen, bei denen dies "normal" ist, dass sie sehr genau bei
Fliesskommaoperationen sind.
z.B. Clarion: Dezimal mit einer Genauigkeit von 31 Stellen vor und nach
dem Komma. (Intern als BCD)
 

Wildcard

Top Contributor
Nöö, es ist sicherlich eine andere interne Darstellung von Dezimalzahlen.
Es gibt Sprachen, bei denen dies "normal" ist, dass sie sehr genau bei
Fliesskommaoperationen sind.
Jede Sprache die sich an die IEEE 754 hält (was meines wissens fast jede 'gängige' Sprache' einschließt) kann Zahlen wie 0.1 nicht richtig als Fließkommazahl darstellen(eigentlich überhauptnicht rein binär).
Daher schließe ich mich Roar und Beni an, und sage das ist gerundet...
 

0xdeadbeef

Top Contributor
Die interne Zahlendarstellung ist in C#/C/Java definitiv die gleiche (jedenfalls solange man in Java nicht strictmath benutzt). Allerdings habe ich auch den Eindruck, daß die Standardlibraries anderer Sprachen "geschickter" runden.
Daß dort aber auch nur mit Wasser gekocht wird, kann man leicht zeigen:
0.2*0.2-0.04 sollte 0 ergeben, ergibt aber auch in C++ in double gerechnet 6.93889390391e-018.
 
S

stev.glasow

Gast
@Illus Test:

C#

Code:
using System;

namespace MyTest
{
	public class FloatingPointTest
	{
		public static void Main (string[] args)
		{
			double i = 0;
			for (double d = 0; d < 5; d += 0.2){

				double dd  = d * 10;
				bool b = dd == i;
				Console.Out.WriteLine (dd + " == " + i + ": " + b);
				i+=2;
			}
			Console.Out.WriteLine (0.2*0.2-0.04 );
		} 
	}
}
0 == 0: True
2 == 2: True
4 == 4: True
6 == 6: False
8 == 8: True
10 == 10: True
12 == 12: True
14 == 14: True
16 == 16: False
18 == 18: True
20 == 20: False
22 == 22: False
24 == 24: True
26 == 26: True
28 == 28: False
30 == 30: False
32 == 32: False
34 == 34: False
36 == 36: False
38 == 38: False
40 == 40: False
42 == 42: False
44 == 44: False
46 == 46: False
48 == 48: False
6,93889390390723E-18



java:
Code:
public class FloatingPointTest
{
	public static void main (String[] args)
    {
		double i = 0;
        for (double d = 0; d < 5; d += 0.2){

           double dd  = d * 10;
           boolean b = dd == i;
           System.out.println (dd + " == " + i + ": " + b);
           i+=2;
        }
		System.out.println  (0.2*0.2-0.04 ); 

	}
}

0.0 == 0.0: true
2.0 == 2.0: true
4.0 == 4.0: true
6.000000000000001 == 6.0: false
8.0 == 8.0: true
10.0 == 10.0: true
12.0 == 12.0: true
14.0 == 14.0: true
15.999999999999998 == 16.0: false
18.0 == 18.0: true
19.999999999999996 == 20.0: false
21.999999999999996 == 22.0: false
24.0 == 24.0: true
26.0 == 26.0: true
28.000000000000004 == 28.0: false
30.000000000000004 == 30.0: false
32.00000000000001 == 32.0: false
34.00000000000001 == 34.0: false
36.00000000000001 == 36.0: false
38.000000000000014 == 38.0: false
40.00000000000001 == 40.0: false
42.000000000000014 == 42.0: false
44.000000000000014 == 44.0: false
46.000000000000014 == 46.0: false
48.000000000000014 == 48.0: false
6.938893903907228E-18
 
G

Gast

Gast
double werte kann man nicht auf gleichheit prüfen nur auf
< oder > , und sich einer beliebigen genauigkeit einigen
z.b ob es 0 ist
while (!(doubleWert > 1E-6))
.
.
.
und wenn es dann halt kleiner ist hat man 0
 
S

stev.glasow

Gast
Klar kann man, man sollte nur drauf achten was man damit vorher gemacht hat. Evtl. vor der Prüfung runden.
Oder was meinst?
 

Bleiglanz

Gesperrter Benutzer
man SOLL nicht auf = prüfen

=> in .NET gibts da ne eigene Konstante (Epsilon)

=> in Java Double.MIN_VALUE
 

The_S

Top Contributor
Wildcard hat gesagt.:
Wildcard hat gesagt.:
Dann erklär mir doch mal wie du z.B. 0.1 korrekt als Fließkommazahl darstellen willst?
Illuvatar hat gesagt.:
Naja, andere Sprachen schaffen das auch :?
Nicht wirklich, das ist ein Problem der Fließkommazahlen und die sind Standard...

Und noch ein Auszug aus einem Buch:

VB 6 in 21 Tagen hat gesagt.:
Strings, Boolesche Werte, Währungsdaten, Datumswerte, Zeitwerte und die Integer-Datentypen (Byte, Integer und Long) können auf Gleichheit miteinander verglichen werden. Versuchen Sie jedoch nicht, zwei Werte mit einfacher oder mit doppelter Genauigkeit zu vergleichen. Aufgrund der Methode, wie Visual Basic Daten mit einer bestimmten Genauigkeit speichert, erscheinen zwei Werte mit einfacher Genauigkeit möglicherweise ungleich, weil Visual Basic intern eine Rundung für solche Werte vornimmt. Wenn Sie zwei Variablen mit gleicher Genauigkeit vergleichen möchten, subtrahieren Sie sie und vergleichen die Differenz, um zu prüfen, ob sie annähernd gleich sind. Diese Codierung ist mühsam, vermeiden Sie sie also, wo immer Sie können.
 

thE_29

Top Contributor
Btw.: C Code, wegen eurer "vorformatieren C#" Ausgabe:

Code:
	for (double d = 0; d < 5; d += .2){
          printf("%lf\n",d);
       }

C hat gesagt.:
0.000000
0.200000
0.400000
0.600000
0.800000
1.000000
1.200000
1.400000
1.600000
1.800000
2.000000
2.200000
2.400000
2.600000
2.800000
3.000000
3.200000
3.400000
3.600000
3.800000
4.000000
4.200000
4.400000
4.600000
4.800000


Nachtrag:

Code:
int main(int argc, char* argv[])
{
	
	double i = 0;
	for (double d = 0; d < 5; d += 0.2)
	{
      double dd  = d * 10;
      bool b = dd == i;
      printf("%lf == %lf : %d\n",dd,i,b);
      i+=2;
    }
    printf("\n\n%lf",0.2*0.2-0.04 ); 

	return 0;
}

C hat gesagt.:
0.000000 == 0.000000 : 1
2.000000 == 2.000000 : 1
4.000000 == 4.000000 : 1
6.000000 == 6.000000 : 0
8.000000 == 8.000000 : 1
10.000000 == 10.000000 : 1
12.000000 == 12.000000 : 1
14.000000 == 14.000000 : 1
16.000000 == 16.000000 : 0
18.000000 == 18.000000 : 1
20.000000 == 20.000000 : 0
22.000000 == 22.000000 : 0
24.000000 == 24.000000 : 1
26.000000 == 26.000000 : 1
28.000000 == 28.000000 : 0
30.000000 == 30.000000 : 0
32.000000 == 32.000000 : 0
34.000000 == 34.000000 : 0
36.000000 == 36.000000 : 0
38.000000 == 38.000000 : 0
40.000000 == 40.000000 : 0
42.000000 == 42.000000 : 0
44.000000 == 44.000000 : 0
46.000000 == 46.000000 : 0
48.000000 == 48.000000 : 0


0.000000

Nachtrag2: Irgendwie sind die boolschen Vergleiche bei C,C# und Java gleich :)

Nur die Rechnung kommt in C richtig raus ^^
 

Reality

Top Contributor
Ob 0,999999999 oder 1, das ist egal, weil es ein und dasselbe sind.

1/9 = 0,1111111111111111111111111

0,11111111111 * 9 = 0,999999999999999

1/9 * 9 = 1 (kürzt sich raus)

Ergo => 0,9999999999999999 und 1 sind dasselbe.
 

thE_29

Top Contributor
PI = genau 3 :D


Naja, für mich sollten das nicht dasselbe sein, wwweil was ist wenn du wirklich mal 0,9999999 haben willst und net 1 ??
 

Reality

Top Contributor
sky80 hat gesagt.:
thE_29 hat gesagt.:
Naja, für mich sollten das nicht dasselbe sein, wwweil was ist wenn du wirklich mal 0,9999999 haben willst und net 1 ??
Mathematisch betrachtet ist es nun aber so, dass es das gleiche ist!

0,999999999999999 entspricht nunmal 9/9 und ist somit 1!

Sorry, aber die Mathematik kann ich nicht so schnell ändern ;-)
Jo, genau. Man kann es auch mit Worten erklären. Wenn 0,99999999 unendlich viele 9er hat, dann ist die Differenz zwischen 0,999999999 und 1 unendlich klein => ein und dasselbe.

Liebe Grüße
Reality
 

thE_29

Top Contributor
Jo, nur muss man auch sagen das

0,111 != 1/9 ist!

Sondern

0,111° = 1/9 (wobei ° für peridoisch ist)

Da ist halt wieder das Problem, wenn man halt wirklich mit so einer Zahl rechnet (die nicht periodisch ist, sondern einfach nur so aussieht)
 
L

LazyBoy

Gast
Der Thread ist zwar schon etwas älter, aber ich wollt noch was dazu sagen.
Und zwar gibt es natürlich in java auch die möglichkeit "genau" zu rechnen, und zwar mit dem package java.math, dort finden sich die Klassen BigDecimal , BigInteger und MathContext damit gibt es die Möglichkeit so genau zu rechnen wie man will, man hat nämlich die völlige Kontrolle darüber wie gerundet wird. Wie genau das funktioniert weiss ich leider auch nicht mehr, aber steht alles in der API. Ist sehr interessant.
 
Status
Nicht offen für weitere Antworten.

Oben