Rolf B: Brett vorm Kopf. Finde den Fehler nicht.

Beitrag lesen

Hallo Joachim,

ok, darauf geht Janoschs Artikel nicht ein. Runden hilft Dir nicht. Wenn Du 42.01 auf 2 Nachkommastellen rundest, ist es immer noch eine Fließkommazahl die nicht genau dargestellt werden kann.

Was Du tun musst, hängt von deiner Problemstellung ab. Wenn Du immer genau 2 Nachkommastellen hast, z.B. weil es Geld ist, dann rechne nicht mit Euro, sondern mit Cent. D.h. wenn Du "42.01" hereinbekommst, multipliziere es mit 100, addiere 0,5 und mache mit intval() eine Integerzahl draus.

Könnte man in einer Funktion kapseln:

function toCents($euro) {
   return intval($euro * 100 + 0.5);
}

Wenn Du dagegen mit tatsächlichen Fließkommazahlen rechnen musst, dann ist der Test auf Gleichheit nicht mehr realisierbar. Statt dessen musst Du prüfen, ob die beiden Zahlen „nah genug“ beieinander liegen. Was „nah genug“ ist, kommt auf den Einzelfall an und muss bei jeder Rechnung neu überlegt werden. Du musst bedenken, dass ein double 15 signifikante Ziffern hat. Wenn deine Werte im Bereich von 1 liegen, dann liegt die "Auflösung" bei 1E-15. Wenn deine Werte aber im Bereich von zehn Millionen liegen (was 7 Vorkommastellen sind), hast Du nur noch 8 Nachkommastellen. Die Auflösung liegt bei 1E-8.

Dein Schwellwert für "gleich genug" sollte 1-2 Größenordnungen über der numerischen Auflösung liegen, um Fehlerfortpflanzung in Rechnungen zu berücksichtigen.

Statt $a == $b kannst Du also zum Beispiel abs($a - $b) < 1E-13 testen. Oder $a < $b - 1E-12 statt $a < $b. Das Spaceship kannst Du bei float vergessen. Und wie gesagt: Statt 1E-12 kann auch mal 1E-8 oder 0.001 korrekt sein, je nach Größenordnung der Zahlen, mit denen Du hantierst.

Wenn Du vorher mit wilden Formeln herumgerechnet hast, musst Du deine Formeln eigentlich noch auf Fehlerfortpflanzung untersuchen, um zu wissen, wie groß dein Schwellwert für "nicht mehr gleich" sein muss. Je nachdem, wie Du rechnest, kann es auch sein, dass das Umstellen einer Formel den Rechenfehler massiv verbessert oder verschlimmert. Man kann statt Fehlerrechnung aber auch Testprogramme schreiben und die Formel mit verschiedenen Werten testen, um ein Gefühl für den durch Probieren herausbekommen.

Aus gutem Grund ist Richtig Rechnen (a.k.a. Numerik) eins der gruseligsten Fächer im Mathe- oder Informatik-Studium.

Rolf

--
sumpsi - posui - obstruxi
0 47

Brett vorm Kopf. Finde den Fehler nicht.

Joachim
  • php
  1. -1
    Operator
    1. 0
      dedlfix
    2. 0
      Graf Bit
      1. 0
        Der Martin
      2. 0
        Rolf B
        1. 0
          Der Martin
        2. 0

          Float binär darstellen

          Graf Bit
          • datenvisualisierung
          • php
          1. 0
            Rolf B
  2. 0
    Erik K.
  3. 0
    Der Martin
    1. 0
      Joachim
      1. 0
        Der Martin
        1. 0
          Joachim
          1. 0

            Brett vorm Kopf. Finde den Fehler nicht. Oder verstehe settype nicht. :-/

            Joachim
            1. 0
              dedlfix
              1. 0
                Joachim
                1. 0
                  Rolf B
        2. 0
          Joachim
          1. 0
            Der Martin
            1. 0
              Joachim
      2. 0
        encoder
        1. 0
          Rolf B
          1. 0
            encoder
  4. 0
    Rolf B
    1. 0
      Der Martin
      • php
      • selfhtml-wiki
      1. 0
        Rolf B
        1. 0
          Der Martin
          1. 0
            Matthias Apsel
        2. 0
          Matthias Apsel
      2. 0
        Matthias Apsel
        1. 0
          Rolf B
    2. 0
      Joachim
      1. 0
        Joachim
      2. 2
        Der Martin
        1. 0
          Joachim
      3. 2
        Rolf B
        1. 0
          Der Martin
          1. 0
            Matthias Apsel
            • sonstiges
            1. 0
              Rolf B
              1. 0
                Der Martin
        2. 0
          Joachim
          1. 0
            Der Martin
        3. 0
          Tabellenkalk
          1. 0
            Der Martin
            1. 0
              MudGuard
          2. 0
            Rolf B