Rundungsproblem
brigitte Kunz
- perl
Hallo.
Kann jemand sich folgenden Effekt erklären:
beim Multiplizieren und Dividieren rundet Perl aus irgendeinem Grund die Ergebnisse, wenn die Ausgangswerte errechnet wurden.
Werden die Ausgangswerte mit Konstanten vorbelegt, wird nicht gerundet.
Beispiele:
#Erster Versuch: Es wird gerundet
my $zinssatz = 0.055;
my $jahressumme = $gesamtsumme * 12 / $runtime;
my $volume = $zinssatz * ($jahressumme - ($jahressumme % 1000000)) / 1000000; #Anzahl Millionen in $jahressumme wird errechnet
#Jahressumme = 3737500 ist in einem vorangehenden Abschnitt errechnet worden; Es sollte sich $volume = 0.055 * 3 = 0.165 ergeben.
Perl liefert aber 0 zurück.
#Zweiter Versuch: Jahressumme wird fest vorgegeben, kein Runden, Ergebnis OK.
my $volumenzinssatz = 0.055;
my $jahressumme = 3737500; #fest vorgegeben
my $csm_volume = $volumenzinssatz * ($jahressumme - ($jahressumme % 1000000)) / 1000000;
#Wie erwartet wird 0.165 zurückgeliefert.
Kann mir jemand erklären, wie es zu dem Effekt kommt und wie er sich umgehen läßt? (Ganzzahlmodus ist nicht eingeschaltet!)
Gibt es eventuell am Server Einstellungen, die das Rundungsverhalten beeinflussen?
Nach zwei Tagen Rumprobierens bin ich mit meinem Latein am Ende. Das Manual sagt hier nur lapidar: 'Perl rechnet exact so wie Sie es erwarten.' Sind meine Erwartungen überzogen?
Für jegliche Hilfe bedanke ich mich im voraus recht herzlich.
Brigitte Kunz
Nach zwei Tagen Rumprobierens bin ich mit meinem Latein am Ende. Das Manual sagt hier nur lapidar: 'Perl rechnet exact so wie Sie es erwarten.' Sind meine Erwartungen überzogen?
Ich erhalte nur wenn ich dein Beispiel versuche zum laufen zu bringen:
D:\Internet\HtDocs\Struppi\perl>perl test.pl
Global symbol "$gesamtsumme" requires explicit package name at test.pl line 7.
Global symbol "$runtime" requires explicit package name at test.pl line 7.
"my" variable $jahressumme masks earlier declaration in same scope at test.pl l
ne 15.
Execution of test.pl aborted due to compilation errors.
Da läßt sich natürlich nicht viel sagen, ausser Perl rechnet exakt so wie du es erwartest.
Struppi.
Hallo.
Hi,
my $jahressumme = $gesamtsumme * 12 / $runtime;
Versuchs mal mit:
my $jahressumme = $gesamtsumme * 12.0 / $runtime;
Diesen Effekt hatte ich auch schon mal, dass Perl wie bei dir alles in Ganzzahlen umgewandelt hatte. So wie vorgeschlagen, funktionierte es dann.
astelix
gudn tach!
my $jahressumme = $gesamtsumme * 12 / $runtime;
Versuchs mal mit:
my $jahressumme = $gesamtsumme * 12.0 / $runtime;Diesen Effekt hatte ich auch schon mal, dass Perl wie bei dir alles in Ganzzahlen umgewandelt hatte.
kann es sein, dass du hier unsinn erzaehlst?
"By default, Perl assumes that it must do most of its arithmetic in floating point." (quelle: perldoc perlop)
"Perl provides the C-like operators * (multiply), / (divide), and % (modulo). The * and / work exactly as you would expect, multiplying or dividing their two operands. Division is done in floating point, unless you've used the integer pragmatic module." (quelle: programming perl, 3rd edition, o'reilly)
prost
seth
Hell-O!
Kann jemand sich folgenden Effekt erklären:
Als Lektüre empfehlen sich der Abschnitt Data:Numbers in perlfaq4 und der Abschnitt Storing Numbers in perlnumber.
beim Multiplizieren und Dividieren rundet Perl aus irgendeinem Grund die Ergebnisse, wenn die Ausgangswerte errechnet wurden.
Perl hat halt nur eine beschränkte Möglichkeit, Zahlen intern darzustellen, nämlich binär. Das funktioniert halt bei manchen Zahlen gut, bei den meisten jedoch nur näherungsweise:
printf "%.30g", 0.125;
# 0.125
printf "%.30g", 0.825;
# 0.824999999999999955591079014994
Um hier quasi den Überblick zu behalten, ist Perl zum Runden gezwungen, seine Grenzen findet es hier beim verwendeten Betriebssystem. Da du mit keiner Silbe erwähnst, welche Größenordnungen $gesamtsumme und $runtime haben, kann man nur raten, ob überhaupt und wenn ja welche Variable hier möglicherweise der Übeltäter ist.
#Erster Versuch: Es wird gerundet
#Jahressumme = 3737500 ist in einem vorangehenden Abschnitt errechnet worden; Es sollte sich $volume = 0.055 * 3 = 0.165 ergeben.
Perl liefert aber 0 zurück.
Bist du sicher? Hast du dir mal mittels printf die Zwischenschritte ($Jahressumme bzw. $volume) ausgeben lassen?
#Zweiter Versuch: Jahressumme wird fest vorgegeben, kein Runden, Ergebnis OK.
Das lässt darauf schließen, dass einer der Variablen, die du in der Berechnung von $jahressumme verwendest, zu dem beobachteten Ergebnis führt. Welche das ist, kann man ohne mehr Details nicht sagen. Btw, du solltest ggf. überlegen, auf die Module Math::BigFloat bzw. Math::BigInt oder ein anderes passendes aus dieser Modulfamilie zurückzugreifen.
Gibt es eventuell am Server Einstellungen, die das Rundungsverhalten beeinflussen?
Gute Frage, kann ich mir eigentlich nicht vorstellen.
Nach zwei Tagen Rumprobierens bin ich mit meinem Latein am Ende. Das Manual sagt hier nur lapidar: 'Perl rechnet exact so wie Sie es erwarten.' Sind meine Erwartungen überzogen?
Naja, Perl ist von Haus aus eben kein Taschenrechner :-)
Siechfred