Jörg Wittemeier: cgi kann nicht rechnen

Hallo !!

Habe ein kleines, aber nicht unwichtiges cgi-Problem (Perl):

$test=3*529.95;
print "$test";

Die Ausgabe sieht dann so aus:

1589.8500000000001364

Sobald keine ganzen Zahlen im Spiel sind kommt es
zu diesen Merkwürdigkeiten. Auch bei einer Division !

Nun habe ich vor einigen Tagen diese Frage hier im Forum
schon einmal gestellt und als Antwort "falsche Serverkonfiguration"
erhalten. Habe den Server gewechselt und: gleicher Fehler !
Kann doch kein Zufall sein. Oder doch?

Gruß
Jörg

  1. Hallo Jörg !!

    $test=3*529.95;
    print "$test";

    Die Ausgabe sieht dann so aus:

    1589.8500000000001364

    Ich muß vorausschicken, ich bin eine Patchworktante, die das Programmieren nicht gelernt hat.
    Deshalb ist ein Tip von mir nicht der Weisheit letzter Schluß.

    Aber ich lasse mich von solchen Sachen nicht ärgern, sondern arbeite nur mit ganzen Zahlen und dividiere erst zum Schluß.
    Will sagen, z.B. in meinem JavaScript-Warenkorb wird mit Pfennigen gerechnet,  und das Ergebnis zum Schluß erst in DM ausgegeben
    Das würde dann wohl so aussehen:
    3*52995/100

    Gruß Jutta

    1. Hallo Jörg !!

      $test=3*529.95;
      print "$test";

      Die Ausgabe sieht dann so aus:

      1589.8500000000001364
      Ich muß vorausschicken, ich bin eine Patchworktante, die das Programmieren nicht gelernt hat.
      Deshalb ist ein Tip von mir nicht der Weisheit letzter Schluß.

      Aber ich lasse mich von solchen Sachen nicht ärgern, sondern arbeite nur mit ganzen Zahlen und dividiere erst zum Schluß.
      Will sagen, z.B. in meinem JavaScript-Warenkorb wird mit Pfennigen gerechnet,  und das Ergebnis zum Schluß erst in DM ausgegeben
      Das würde dann wohl so aussehen:
      3*52995/100

      Gruß Jutta

      Hallo Jutta !

      Leider hilft mir das auch nicht weiter.
      Unter Perl ergibt 3*52995/100
      genau 1589,8499999999999091  :-((
      Es handelt sich übrigens auch um ein Shopping-Sytem.
      Unter UNIX läuft es, aber unter einem anderem
      Betriebssystem nicht:
      Gruß
      Jörg

  2. Hallo Joerg,

    $test=3*529.95;
    print "$test";
    Die Ausgabe sieht dann so aus:
    1589.8500000000001364

    Scheint tatsaechlich eher was mit dem Server-Rechner zu tun zu haben. Hab's gerade mal bei mir lokal als kleines CGI-Script getestet und heraus kam 1589.85.

    Viele Gruesse
      Stefan Muenz

    1. Hallo Joerg,

      $test=3*529.95;
      print "$test";
      Die Ausgabe sieht dann so aus:
      1589.8500000000001364

      Scheint tatsaechlich eher was mit dem Server-Rechner zu tun zu haben. Hab's gerade mal bei mir lokal als kleines CGI-Script getestet und heraus kam 1589.85.

      Viele Gruesse
        Stefan Muenz

      Hallo Stefan !

      Habe mein Shopping-System nun auf 3 !  Servern getestet.
      Der dritte war ein UNIX - Server und dort lief die Multiplikation
      perfekt und ohne Rechenfehler.
      Weiß leider noch nicht, mit welchem Betriebssystem die zwei anderen
      laufen. War jedenfalls nicht UNIX. Muß mich noch kundig machen.
      Kann doch aber nicht die Lösung sein, daß Berechnungen mit
      Perl nur unter bestimmten Betriebstsystemen laufen.
      Gruß
      Jörg

  3. Hallo !!

    Habe ein kleines, aber nicht unwichtiges cgi-Problem (Perl):

    $test=3*529.95;
    print "$test";

    Die Ausgabe sieht dann so aus:

    1589.8500000000001364

    Hallo Jörg!

    Dein Problem ist prinzipieller Natur: Die Zahl
    529.95, welche zunächst recht harmlos wirkt,
    wird in der Binärdarstellung des Computers zu einem
    periodischen, nicht-abbrechenden Dezimalbruch.

    (Beispiel:
      0.95 = 1-1/20,

    1/20 (dezimal) = 1/10100 (binär)
      = 0.0000110011001100....(binär)
    )
    Jetzt kommt es eben darauf an, wieviele Binärstellen der Perl-Interpreter
    für eine Real-Zahl verwendet. In den letzten Stellen ist ein Rundungsfehler
    immer vorprogrammiert.

    Bei Zahlen, die sich glatt darstellen lassen, z.B. 0.25 = 0.01(binär),
    sollten derartige Probleme dagegen nicht auftreten (ausprobieren!).

    Ich habe mit Perl noch nicht viel gemacht, denke aber, daß es
    irgendwelche Operatoren geben müßte, um Zahlen formatiert

    • also z.B. mit genau 2 Nachkommastellen - auszugeben, wie das
      im Falle einer Abrechnungs-Software sowieso sinnvoll ist.
      Die Abweichungen in der 12. Dezimalstelle sind dann sozusagen
      nur noch "von akademischen Interesse".

    Viele Grüße,

    Andreas

    1. Nachtrag:

      probier mal:

      $x=595.95*3;
      $y=int(x*100+0.5)/100;

      print $y/100;

      Damit wird die Rundung auf 2 Nachkommastellen erzwungen.
      Die Rundung sollte jedoch immer erst unmittelbar vor der Ausgabe
      (oder in der Ausgabe) geschehen.

      Viele Grüße

      Andreas

      P.S.: 0.95 (dezimal) wird im Binärsystem zu einem nicht-abbrechenden BINÄR-Bruch
              (Asche über mein Haupt...).

      1. Nachtrag:

        probier mal:

        $x=595.95*3;
        $y=int(x*100+0.5)/100;

        print $y/100;

        Damit wird die Rundung auf 2 Nachkommastellen erzwungen.
        Die Rundung sollte jedoch immer erst unmittelbar vor der Ausgabe
        (oder in der Ausgabe) geschehen.

        Viele Grüße

        Andreas

        P.S.: 0.95 (dezimal) wird im Binärsystem zu einem nicht-abbrechenden BINÄR-Bruch
                (Asche über mein Haupt...).

        Hallo Andreas !

        Danke für die kompetente Antwort. Hat mir insofern weitergeholfen,
        daß ich den Fehler nicht mehr in der Server-Konfiguration gesucht habe.
        Das mit der Rundung funktionierte auch nicht.
        Kam irgenetwas .99999999990123 herraus.

        Hier meine Lösung:

        $ALL=529.95*3;
        $ALL=$ALL+0.001;
        $ALL=substr($ALL,0,index("$ALL",".")+3);
        print "$ALL";

        Die 0.001 addiere ich für die xxx.999999999990123 Ergebnisse.
        Das Ganze hat den netten Nebeneffekt, daß die Ausgabe immer
        mit 2 Stellen hinter dem Komma erfolgt.

        Gruß
        Jörg

        1. Hier meine Lösung:

          $ALL=529.95*3;
          $ALL=$ALL+0.001;
          $ALL=substr($ALL,0,index("$ALL",".")+3);
          print "$ALL";

          Die 0.001 addiere ich für die xxx.999999999990123 Ergebnisse.
          Das Ganze hat den netten Nebeneffekt, daß die Ausgabe immer
          mit 2 Stellen hinter dem Komma erfolgt.

          »»  Gruß

          Jörg

          Hallo Jörg!

          Was machst Du mit Zahlen wie z.B. 14.976?
          Nach Deiner Rundung müßte 14.97 herauskommen, richtig wäre aber 14.98
          Mein Vorschlag ist daher
          $ALL=$ALL+0.005
          in Deinen obigen Zeilen einzusetzen, ferner noch eine
          Fallunterscheidung für negative Zahlen...

          So, jetzt hab' ich mich als Haarespalter geoutet ;-)

          Frage ans Forum: Gibt es wirklich keinen formatierten Print-Befehl unter PERL??

          Viele Grüße

          Andreas

          1. Hallo Andreas !

            Was machst Du mit Zahlen wie z.B. 14.976?

            Kommt bei mir nicht vor. Ist ein Online-Shopping-System
            mit einfacher Multiplikation.
            Werde mir dennoch Gedanken machen (spätestens bei Berechnung der MWST) :-))

            Mein Vorschlag ist daher
            $ALL=$ALL+0.005

            Funzt nicht, da 0.001 ja die .9999999 beseitigen soll.

            Formatieren wäre sicherlich die beste Lösung, aber wie??

            Gruß
            Jörg