Leser: 39
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
my $sub = 'integer1'; my $space = '.' x 25; my ($int,$erwartet); foreach my $test ( .57 * 100,'=57', .58,'=0', 12.345,'=12', 57.00000000000000001,'=57', 0.000000000000001,'=0', 1.01205,'=1', -0.903,'=0', -1.999999999999999,'=-1' ) { if (substr ($test,0,1) eq '=') { $erwartet = substr ($test,1); print " " . ($int eq $erwartet ? ' OK' : " FEHLER! Erwartet \'$erwartet\'") . "\n"; } else { $int = &{$sub} ($test); print "\'$test\'" . substr ($space,0,25 - length ($test)) . "geINTet: \'$int\'" . substr ($space,0,25 - length ($int)); } }
1
2
3
4
5
6
7
8
'57'.......................geINTet: '56'....................... FEHLER! Erwartet '57'
'0.58'.....................geINTet: '0'........................ OK
'12.345'...................geINTet: '12'....................... OK
'57'.......................geINTet: '57'....................... OK
'1e-015'...................geINTet: '0'........................ OK
'1.01205'..................geINTet: '1'........................ OK
'-0.903'...................geINTet: '0'........................ OK
'-2'.......................geINTet: '-1'....................... OK
1 2 3 4 5 6 7
sub integer1 { my $wert = shift ( @_ ) || 0; if ($wert =~ /^([^\.]*)\.([^\.]+)$/) { $wert = $1; } return $wert + 0; }
1
2
3
4
5
6
7
8
'57'.......................geINTet: '57'....................... OK
'0.58'.....................geINTet: '0'........................ OK
'12.345'...................geINTet: '12'....................... OK
'57'.......................geINTet: '57'....................... OK
'1e-015'...................geINTet: '1e-015'................... FEHLER! Erwartet '0'
'1.01205'..................geINTet: '1'........................ OK
'-0.903'...................geINTet: '0'........................ OK
'-2'.......................geINTet: '-2'....................... FEHLER! Erwartet '-1'
1 2 3 4 5 6 7 8 9 10 11 12 13
sub integer2 { my $wert = shift ( @_ ) || 0; if ($wert =~ /\./) { my $neu = ''; for (my $st = 0; $st < length($wert); $st ++) { if (substr($wert,$st,1) eq '.') { last; } else { $neu .= substr($wert,$st,1); } } $neu = 0 if $neu eq ''; $wert = $neu; } return $wert + 0; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
sub integer { my $wert = shift ( @_ ) || 0; if ($wert =~ /e\-\d+$/) { return 0; } if ($wert =~ /\./) { my $neu = ''; for (my $st = 0; $st < length($wert); $st ++) { if (substr($wert,$st,1) eq '.') { last; } else { $neu .= substr($wert,$st,1); } } $neu = 0 if $neu eq ''; $wert = $neu; $wert = 0 if $wert == -0; } return $wert; }
print int(sprintf '%.15f', .57*100);
Quote56
2012-01-17T13:32:13 biancaJa, wenn es so einfach wäre....
Code (perl): (dl )print int(sprintf '%.15f', .57*100);
Quote56
Passt nicht ganz.
perl -e "printf '%.15f', .57 * 100"
Quotedas richtige Resultat liefert. Und das stimmt nach wie vor. Es kann auch gar nicht anders sein, denn in deinem Testskript (aus dem OP) wird an die sub $sub der exakte Wert 57 übergeben. Da kann int() nichts verderben..57 * 100,'=57',
Quote57.00000000000000001,'=57',
-1.999999999999999,'=-1',
2012-01-17T18:12:29 GUIfreundIch habe nur gesagt, dass meine sub mit_sprintf beim TestfallQuotedas richtige Resultat liefert. Und das stimmt nach wie vor..57 * 100,'=57',
2012-01-17T18:12:29 GUIfreundEs kann auch gar nicht anders sein, denn in deinem Testskript (aus dem OP) wird an die sub $sub der exakte Wert 57 übergeben. Da kann int() nichts verderben.
Quoteint : 56
ohne: 57
2012-01-17T18:29:18 bianca2012-01-17T18:12:29 GUIfreundIch habe nur gesagt, dass meine sub mit_sprintf beim TestfallQuotedas richtige Resultat liefert. Und das stimmt nach wie vor..57 * 100,'=57',
Ja, eine Spitzfindigkeit. Klar liefert es das "richtige" Ergebnis. Aber es bringt mir ja nichts, wenn das computerrichtige Ergebnis mathematischer Nonsens ist. 0.57 * 100 ist nun mal nicht 56 sondern 57, egal ob ich das int'e oder nicht :))
2012-01-17T18:29:18 biancaAuf den ersten Blick übergibst du .57*100 an int() und es kommt 56 raus. Rechnest du ohne int() kommt 57 raus, siehe hier:
Quoteint : 56
ohne: 57
2012-01-17T18:29:18 biancaRechnest du ohne int() kommt 57 raus
2012-01-20T18:14:29 topegDie Probleme tauchen immer auf, wenn Fließkommazahlen in Integer umgewandelt werden sollen. int ist hier nur ein Beispiel. Beim Runden passiert genau das selbe.
Das tritt in deinem Fall nur deshalb nicht auf, da mit Zahlen gearbeitet wird, die nahe an einem Integer sind.
2012-01-20T18:14:29 topegNimmt man andere Werte, so taucht das Problem auch wieder auf. Deine Form des Rundens ebenfalls ist nicht zuverlässig. Auch dort kann es zu Fehlern kommen, wenn eine Rationale Zahl als Fließkommazahl nicht darstellbar ist. So was kann man umgehen. So ist es möglich einigermaßen Korrekt zu runden, indem man die Genauigkeit der Darstellung erhört. Das habe ich z.B bei meiner Funktion zum Runden gemacht. Ähnliches kann man auch bei der von bianca angesprochenen Multiplikation mit Integerumwandlung machen.
Gäbe es einfache Lösungen die Schwächen des Computers zu umgehen, so würde ich sie nutzen.
2012-01-20T18:14:29 topegAber einfache Lösungen gibt es nur in Spezialfällen. Generell muss man größeren Aufwand treiben.
EDIT:
Wobei int($wert*100) ein solcher Spezialfall ist. Da kann man schreiben int($wert*100+0.001) damit werden zu kleine Werte "angehoben". Insofern hast du Recht. Das lässt sich aber nicht so einfach generalisierten.