Rechnet PHP falsch?

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Rechnet PHP falsch?

    Hallo zusammen!

    Ich habe eine kleine Routine geschrieben, die einfach zwei double-Zahlen subtrahieren soll. Leider bekomme ab 256 falsche Werte. Ich benutze Apache/1.3.12 und PHP Version 4.0.3pl1. Anbei ein Ausschnitt aus der Routine und dem Ergeniss.

    Vielleicht kann mir jemand einen Tipp geben, ob ich was falsch mache oder ob da ein Bug vorliegt.

    Schöne Grüße,
    War_Lord_II

    Skript:
    for ($i=250; $i<=300; $i=$i+1) {
    echo $i."; ";
    (double)$j=(double)$i+0.34;
    echo $j."; ";
    $m=$j-$i;
    echo $m."<br>\n";
    }

    Ergebnisse:
    250; 250.34; 0.34
    251; 251.34; 0.34
    252; 252.34; 0.34
    253; 253.34; 0.34
    254; 254.34; 0.34
    255; 255.34; 0.34
    256; 256.34; 0.33999999999997
    257; 257.34; 0.33999999999997
    258; 258.34; 0.33999999999997
    259; 259.34; 0.33999999999997
    260; 260.34; 0.33999999999997
    261; 261.34; 0.33999999999997
    [...]


  • #2
    Das sind Rundungsfehler.
    ne Lösung kann ich hier aus dem Stegreif und ohne Austesten nicht bieten, aber eine Erklärung, wie es dazu kommt


    Jede Fließkommazahl (floating point -> float; double precision -> double, wobei das mit dem double precision hier allerdings nicht sehr überzeugend ist) besteht aus Mantisse und Exponent.
    Das ist vom Taschenrechner oder vom Windows-Rechner (mit wissenschaftlicher Schreibweise) bekannt: 1.65 e+1 = 16.5
    Nu speichert der Rechner aber binär und das 16.5 in binär heißt 10000.1 = 100001 e-1.

    Demnach ist 256.34 = 100000000... ähm
    Code:
    bit Wert         Rest
     0  0.5          0.34
     1  0.25         0.09
     0  0.125
     1  0.0625       0.0275
     0  0.03125
     1  0.015625     0.011875
     1  0.0078125    0.0040625
     1  0.00390625   0.00005625
    100000000.01010111(uswusf)
    Kurz: was in dezimal rund aussieht, ist es in binär nicht unbedingt. Bei den großen Zahlen rundet der Rechner automatisch, aber beim Subtrahieren geht das dann verloren.

    Falls du nur mit zwei stellen hinter dem Komma rechnest ist die Lösung aber ganz einfach: $m = round ($j-$i, 2);
    mein Sport: mein Frühstück: meine Arbeit:

    Sämtliche Code-Schnipsel sind im Allgemeinen nicht getestet und werden ohne Gewähr auf Fehlerfreiheit und Korrektheit gepostet.

    Kommentar


    • #3
      Schönen Dank!

      Soweit konnte ich das nachvollziehen, aber noch zwei Dinge:

      1) Ist es nicht auffällig, daß es genau bei 256, also genau dann, wenn die Mantisse größer als ein Byte wird, auftritt?

      und 2) Sagen wir ich wollte eine naive if-Klausel verwenden, wer mach sich die Mühe und rundet sein Ergebnis, bevor es in der If-Klausel testet? Denn laut Skript wäre ($m>=0.34) immer wahr, aber ab $i=256 müßte die if-Klausel falsch wieder geben.

      Aber mit einer Rundung kann ich leben. Deshalb nochmals schönen Dank und Grüße von

      War_Lord_II

      Kommentar


      • #4
        hi

        wenn du es wirklich mal genau haben willst:

        IV. Mathematische Funktionen mit beliebiger Genauigkeit

        http://php.net/manual/de/ref.bc.php

        greets
        ------------------------
        http://swisswebgroup.com
        ------------------------

        Kommentar


        • #5
          Original geschrieben von War_Lord_II
          1) Ist es nicht auffällig, daß es genau bei 256, also genau dann, wenn die Mantisse größer als ein Byte wird, auftritt?
          öhm ... 100000000.01010111 sind wesentlich mehr als 8 Stellen oder? die Mantisse hier hat kleine 17 Bit.
          Nimm statt 0.34 mal 0.17, dann wird der Fehler schon bei 128 auftreten.
          mein Sport: mein Frühstück: meine Arbeit:

          Sämtliche Code-Schnipsel sind im Allgemeinen nicht getestet und werden ohne Gewähr auf Fehlerfreiheit und Korrektheit gepostet.

          Kommentar

          Lädt...
          X