Laden...

schleifen in 0.1er schritten

Erstellt von numpsy vor 15 Jahren Letzter Beitrag vor 15 Jahren 5.769 Views
N
numpsy Themenstarter:in
231 Beiträge seit 2007
vor 15 Jahren
schleifen in 0.1er schritten

for (Double i = 0.1; i <= 1.0; i++)
{
}

wie geht das? i+0.1 ging nicht

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo numpsy,

i += 0.1

Ist wegen der potentiellen Rundungsfehler allerdings gefährlich, es sei denn, du nimmst decimal.

herbivore

265 Beiträge seit 2006
vor 15 Jahren

@herbivore:
das i kann man doch ruhig als double lassen, dann Rundungsfehler treten doch nicht bei der Addition bei der Laufvariablen auf?

-=MasterMax=-

946 Beiträge seit 2008
vor 15 Jahren

Doch Rundungsfehler treten auf: bei zer Zählung von 0 bis 10: d=9.99999999999998.

Um die Rundungsfehler zu vermeiden kannst du auch:
:::

Ich habe folgenden Tests durchgeführt:

for (decimal m = 0; m < 1000000; m += 0.1m) ;                //Dauer 1: 1446ms
double d2; for (int i = 10; i < 10000000; i++) d2 = i / 10d; //Dauer 2: 156ms

Edit: Meine Variante ist schneller 😄.
Hier noch der Code:

            const int max1 = 1000000, max2 = max1 * 10;
            DateTime a, b, c;
            a = DateTime.Now;
            for (decimal m = 0; m < max1; m += 0.1m) ;               //Dauer 1: 479m
            b = DateTime.Now;
            double d2; for (int i = 10; i < max2; i++) d2 = i / 10d; //Dauer 2: 157ms
            c = DateTime.Now;
            MessageBox.Show("Dauer 1: " + b.Subtract(a).Milliseconds + "ms\r\n" +
                            "Dauer 2: " + c.Subtract(b).Milliseconds + "ms");

M
125 Beiträge seit 2008
vor 15 Jahren

Es treten sehr schnell Rundungsfehler auf!
Bsp:

 double sum = 0;
        for (int i = 0; i < 10; i++)
        {
            sum = sum + 0.1;
        }
// Ausgabe: 0.99999999999999989

ich würde nicht in 0.1'er Schritten aufzählen, sondern mit 1'er Schritten und würde in der Schleife mit i/10 rechnen.

Gruß
mrdjoker

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo MasterMax,

das i kann man doch ruhig als double lassen, dann Rundungsfehler treten doch nicht bei der Addition bei der Laufvariablen auf?

doch, es tritt sogar schon ein Rundungsfehler bei der Repräsentation von 0.1 als double auf, also bevor überhaupt damit gerechnet wurde.

herbivore

143 Beiträge seit 2008
vor 15 Jahren

WOW, hab das gerade echt mal ausprobiert. Ich merk ich habe einfach noch nicht genug praktische Erfahrung.
Da tritt doch wirklich plötzlich so ein komischer Rundungsfehler auf. Hab bis gerade gedacht, dass sowas erst an den Grenzen von double passiert.

Gruß Timo

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo Omit,

Hab bis gerade gedacht, dass sowas erst an den Grenzen von double passiert.

Das solltest du weiterhin denken, denn es passiert ja an den Grenzen von double. 0.1 ist als binäre Fließkommazahl periodisch, das heißt innerhalb der Grenzen von double nicht exakt darstellbar: 0,000110011001100110011...

BTW: Dieser Fehler hat schon Leben gekostet: Runder Fehler: Das Versagen der Patriot-Abwehrrakete.

herbivore

143 Beiträge seit 2008
vor 15 Jahren

Ja, so langsam kommt es mir wieder. Erstes Semester Rechnersysteme, als ich in ASM programmieren durfte und es um Alus ging, war da auch irgendwas mit der Gleitkommadarstellung. 😉
Ist halt immer noch ein unterschied irgendwo Wissen rumliegen zu haben oder es verknüpft und parat zu haben.

Gruß Timo

265 Beiträge seit 2006
vor 15 Jahren

Hey Wow, habs auch gerade mal programmiert...


string s = "";
            for (double d = 0; d < 10; d += 0.1)
            {
                s += d.ToString()+ "    ";
            }
            s += Environment.NewLine;
            s += Environment.NewLine;
            for (int i = 0; i < 100; i++)
            {
                s += ((double)i/10).ToString() + "    ";
            }
            MessageBox.Show(s);

Ergebnis


---------------------------

---------------------------
0    0,1    0,2    0,3    0,4    0,5    0,6    0,7    0,8    0,9    1    1,1    1,2    1,3    1,4    1,5    1,6    1,7    1,8    1,9    2    2,1    2,2    2,3    2,4    2,5    2,6    2,7    2,8    2,9    3    3,1    3,2    3,3    3,4    3,5    3,6    3,7    3,8    3,9    4    4,1    4,2    4,3    4,4    4,5    4,6    4,7    4,8    4,9    5    5,1    5,2    5,3    5,4    5,5    5,6    5,7    5,8    5,9    5,99999999999999    6,09999999999999    6,19999999999999    6,29999999999999    6,39999999999999    6,49999999999999    6,59999999999999    6,69999999999999    6,79999999999999    6,89999999999999    6,99999999999999    7,09999999999999    7,19999999999999    7,29999999999999    7,39999999999999    7,49999999999999    7,59999999999999    7,69999999999999    7,79999999999999    7,89999999999999    7,99999999999999    8,09999999999999    8,19999999999999    8,29999999999999    8,39999999999999    8,49999999999999    8,59999999999999    8,69999999999999    8,79999999999998    8,89999999999998    8,99999999999998    9,09999999999998    9,19999999999998    9,29999999999998    9,39999999999998    9,49999999999998    9,59999999999998    9,69999999999998    9,79999999999998    9,89999999999998    9,99999999999998    



0    0,1    0,2    0,3    0,4    0,5    0,6    0,7    0,8    0,9    1    1,1    1,2    1,3    1,4    1,5    1,6    1,7    1,8    1,9    2    2,1    2,2    2,3    2,4    2,5    2,6    2,7    2,8    2,9    3    3,1    3,2    3,3    3,4    3,5    3,6    3,7    3,8    3,9    4    4,1    4,2    4,3    4,4    4,5    4,6    4,7    4,8    4,9    5    5,1    5,2    5,3    5,4    5,5    5,6    5,7    5,8    5,9    6    6,1    6,2    6,3    6,4    6,5    6,6    6,7    6,8    6,9    7    7,1    7,2    7,3    7,4    7,5    7,6    7,7    7,8    7,9    8    8,1    8,2    8,3    8,4    8,5    8,6    8,7    8,8    8,9    9    9,1    9,2    9,3    9,4    9,5    9,6    9,7    9,8    9,9    
---------------------------
OK   
---------------------------


Ich dachte wirklich die beiden wären äquivalent, da ich nur Variante 2 benutze und bei solchen Sachen noch nie Probleme mit Rundungsfehlern hatte...
Naja, wieder was gelernt =)

-=MasterMax=-

M
194 Beiträge seit 2008
vor 15 Jahren

Sollte man auch beachten wenn man einen Vergleich von zwei Double-Zahlen macht, die auf unterschiedliche Weise berechnet wurden. Da kann es nämlich schnell durch die Rundungsfehler dazukommen, dass sie nicht gleich groß sind, obwohl das laut Mathematik so sein müsste. Für solche Fälle setze ich ein Delta ein, das einen gewissen Rundungsfehler erlaubt.

bool IstGleich (double dZahl1, double dZahl2)
{
  bool bRetVal = false;
  double dDelta = 0.000001; //erlaubte Abweichung
  if ((dZahl1 >= dZahl2 - dDelta) && (dZahl1 <= dZahl2 + dDelta))
  {
    bRetVal = true;
  }
  return bRetVal;
}

"Indem Sie über dieses ernste Thema lachen disqualifizieren Sie sich selbst."
mrleeh.de

3.971 Beiträge seit 2006
vor 15 Jahren

In C# wird wenigstens noch die Schleife beim überschreiten der Zählvariable abgebrochen. In VB würde eine Endlosschleife auftreten.


for d as double = 0 to 10 step 0.1
  ...
end for

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

Gelöschter Account
vor 15 Jahren

[FAQ] Double und Float: Fehler beim Vergleich und Rundungsfehler

edit: seit einiger zeit vorbereitet gewesen aber bislang ncoh nciht veröffentlicht.

B
114 Beiträge seit 2007
vor 15 Jahren

Das sicherste wäre doch mit Ganzzahlen zu arbeiten.
Das Runterrechnen auf double/decimal oder wen auch immer kann man dann ja in der Schleife machen.

[Edit]
Ok so ähnlich wurde das ja schon geschrieben. Geht etwas unter bei der ganzen Diskussion um Rundungsfehler.

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo blackman1983,

decimal arbeitet intern ja mit Ganzzahlen, bei denen per - ebenfalls ganzzahligem - Exponent das Komma verschoben wird. Insofern ist das ebenfalls sicher.

herbivore

B
114 Beiträge seit 2007
vor 15 Jahren

Ah ok, wusste ich nicht.
Ich hab glaube noch nie eine Schleife mit decimal gemacht.