Thread Rechenfehler mit Perl ausgleichen (71 answers)
Opened by bianca at 2013-04-27 13:42

tonewheel
 2013-05-01 16:01
#167376 #167376
User since
2006-10-01
182 Artikel
BenutzerIn
[default_avatar]
2013-04-30T20:02:59 hlubenow
...Ich will, daß mir solche Fragen von der Sprache, bzw. vom Interpreter abgenommen werden. Ich will schnell vorankommen! Und deshalb will ich natürlich auch, daß eine Prüfung von "0.57 * 100" ein reines "57" ergibt. Sonst gehe ich erstmal davon aus, daß der Interpreter kaputt ist. Es wäre seine Aufgabe, mich von solchen Low-Level-Fragen fernzuhalten. Wahrscheinlich sollte die Regelung des Problems tatsächlich in den Interpreter eingearbeitet werden.


Dass Module auch semantisch falsch sein können, ist eine andere Sache. Im Thread drehte es sich ja vielmehr um die Genauigkeit des Rechners (und nur vermeintlich um Programmiersprachen). Rein optisch sollte man meinen, dass 0.57 * 100 = 57 sei. Jedoch, während die Zahl 57 sehr einfach zu speichern ist, stellt sich das bei 0.57 (als Dezimalbruch) ganz anders dar! Es ist durchaus nicht so, dass da 'einfach eine Null mit Komma' davor gesetzt wird. Die 57 stellt sich binär dar als 00111001. Die 0.57 ist ein Dezimalbruch, der aus möglichen Binärdarstellungen aufgelöst werden muss:

Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/perl

use warnings;
use strict;

my $b = 0.57;
my $BITS = -24;
my $BASE = 2;

for(my $c = -1; $c >= $BITS; $c--) {
    if (($BASE ** $c) < $b) {
        printf("Bit %2d: %0.15f - %0.15f = %0.15f\n", -$c, $b, $BASE ** $c, $b - $BASE ** $c);
        $b -= $BASE ** $c;
    }
}

(Für Kritiker: Nur im Prinzip anhand der Mantisse, und ohne Exponent dargetellt) Man sieht dann, dass auch nach 24 Bit noch 'Reste' übrig sind. Skaliert man nun diese Zahl mit 100, gehen auf der 'rechten Seite' wichtige Bits verloren die dann unwiederbringlich sind. Mit einer direkten Darstellung der Zahl 57 hat das (weder vorher noch nachher) nichts zu tun.
Das ist aber alles Sache des Rechners selbst, weder die Hostsprache C, noch Perl selbst kann das irgendwie kompensieren. Man kann auch nichts in den Interpreter einbauen, denn wie sollte das aussehen? In dem Fall wäre es wirklich sinnvoll, echte Integer zu benutzen, die nur C, C++, Java und Konsorten bieten. Da nützt es auch nichts, irgendwelche Module zu benutzen, die scheinbar mit Zahlen zur Basis 10 arbeiten. Dies wird nur durch Strings 'emuliert' und ist m.M. absolut nicht performant.
Im gegebenen Fall - d.h. wenn es um Währungen geht, wenn ich das richtig interpretiert habe - sollte man völlig auf Dezimalbrüche verzichten und die Beträge einfach in der Einheit Cent einfordern. D.h statt 1000,00 Euro wird 100000 Cent eingeben. Die Ausgabe mit Komma am Schluss oder zur Gegenkontrolle könnte man z.B. sehr leicht mit einer Sub nachbilden. Übrigens wird diese Art der Eingabe bei mindestens einer mir bekannten, namhaften Bank in D. im Telefonbanking praktiziert, ist also nichtmal ungewöhnlich.
Last edited: 2013-05-01 16:03:03 +0200 (CEST)

View full thread Rechenfehler mit Perl ausgleichen