Hier nun meine Routine zum kaufmännischen Runden mit Perl.
Anlaß: SPRINTF von Perl ist unzuverlässig, schönes Beispiel ist, den Wert
1.345 mit sprintf auf 2 Stellen zu "runden".
Bitte bedient Euch nach Belieben und laßt mir Verbesserungen bitte zukommen:
(ein konkretes Problem habe ich noch: die Nachkommastellen werden größer 3
auch gruppiert. Das würde ich gern abschalten aber wie?) :-)
sub RUNDEN($;$) {
##
## Rundet einen Wert mit beliebig vielen Nachkommastellen KAUFMÄNNISCH(!)
## auf einen Wert mit der angegebenen Zahl Nachkommastellen (max. 3).
## Kaufmännisch heißt im Beispiel mit zwei Stellen:
## 3.45 bleibt 3.45
## aus 3.4510000000001 bis 3.4549999999999 wird 3,45
## aus 3.4550000000001 bis 3.4599999999999 wird 3,46
##
## Außerdem werden Dezimalpunkte eingefügt und aus dem
## Dezimalpunkt wird ein Komma gemacht.
## z.B. aus 1234.56 wird 1.234,56 bei 2 Stellen
##
## Die Nachkommastellen werden mit 0 aufgefüllt wenn
## durch den Wert die angegebene Zahl nicht erreicht wird,
## z.B. aus 3.4 wird 3,400 bei 3 Stellen
##
## Wird aufgerufen mit
## $return = &RUNDEN($wert,$stellen);
## wobei $wert die zu rundende Zahl ist
## und $stellen die Anzahl der zu rundenden Nachkommastellen ist
##
## $return enthält dann den gerundeten Wert von $wert
## oder 0 bei Mißerfolg
##
my ($val,$dec) = @_;
return 0 if ((!defined $val) || (!defined $dec) || ($val=~ /[^-0-9\.]/) ||
($dec=~ /[^-0-9]/) || ($dec<0) || ($dec>3));
$val = (($val + (0.5/(10**$dec)))*100)/100; # mathematisch aufrunden
my $res = int($val*(10**$dec))/(10**$dec); # Nachkommastellen abschneiden
$res =~ y/./,/; # ordentlich formatieren
1 while $res =~ s/(\d)(\d\d\d)\b/$1.$2/; # Grueppchen bilden
return $res;
}
Gruß
M.D.
Vielleicht ist zu diesem Thema auch ein Blick auf Math::Currency wert.
lg,
le
--
"To stop the drip, turn cock to right."
-- On the faucet in a Finnish washroom.
[useless code snipped]
sorry, aber das versteh ich jetzt nicht ganz. was bitte ist an
sprintf unzuverlässig?
#!/usr/local/bin/perl -w
use strict;
my $zahl = 1.345;
my $rundzahl = sprintf "%.2f", $zahl;
print $rundzahl;
ergibt bei mir (Perl 5.00503 und 5.6):
1.35
hätte ich etwas anderes erwarten sollen?
übrigens: für $zahl = 1.343 bekomme ich:
1.34
voller fragen
thoren
8#X
--
----------------------------------------------------------------------
Thoren Johne - 8#X - tho...@southern-division.com
Southern Division Classic Bikes - www.southern-division.com
Ich würde es auch nicht unzuverlässig nennen, aber schau mal unter perldoc
-q round - da steht das u.a. mit kaufmännischen Anwendungen, daß da nicht
immer das raus kommt, was man erwartet. Nützlich ist in diesem
Zusammenhang das Currency-Modul (wurde hier von Lukas bereits angemerkt).
> #!/usr/local/bin/perl -w
> use strict;
>
> my $zahl = 1.345;
>
> my $rundzahl = sprintf "%.2f", $zahl; print $rundzahl;
>
> ergibt bei mir (Perl 5.00503 und 5.6):
> 1.35
bei mir ergibt das unter 5.00503 den Wert 1.34; erst bei 1.236 wird da
aufgerundet.
> voller fragen thoren
> 8#X
fragen minimiert? Dietmar
Nach DIN wird eine *exakte* 5 abgerundet, d.h. in diesem Beispiel muesste
1.345 zu 1.34 gerundet werden. Nur falls die 5 nicht exakt ist (d.h. es gibt
noch weitere Stellen ungleich 0) oder ihrerseits durch abrunden entstanden
ist wird aufgerundet.
jue
:) schon gelesen... danke trotzdem für den hinweis ;)
naja... ich kenne das modul nicht, arbeite aber eigentlich bei
monitären beträgen grundsätzlich mit ganzzahligen pfenningwerten und
rechne nur für die ausgabe auf FP DM beträge um.
aufgrund der generellen problematik der limitierten darstellung von
brüchen auf binär arbeitenden computern scheint mir das auch die
einzig 'brauchbare' lösung zu sein.
manche scheinen probleme damit zu haben so vorzugehen -
ist wohl gewöhnungs/erfahrungssache ;)
gruß
nun... dann scheint das programm vom Michael Döring aber auch nicht nach
DIN zu runden, denn damit bekomme ich exakt den gleichen wert zurück
wie bei sprintf und $zahl = 1.345;
in beiden fällen ist das ergebnis 1.35
Mit ActivePerl 5.004_02 für Windows halt eben nicht, da kommt bei SPRINTF
leider 1.34 raus.
--
Michael Döring, 53840 Troisdorf
Tel 02241 9781-97 -- Fax -96 -- eMail in...@mikdoe.com -- ICQ 12860386
verstehe. gottlob setze ich das schon lange nicht mehr ein ;)
Wer noch einen Fehler findet, bekommt 100 adViews auf ....? :-)
sub RUNDEN($;$) {
##
## Rundet einen Wert mit beliebig vielen Nachkommastellen KAUFMÄNNISCH(!)
## auf einen Wert mit der angegebenen Zahl Nachkommastellen.
## Kaufmännisch heißt im Beispiel mit zwei Stellen:
## 3.45 bleibt 3.45
## aus 3.4510000000001 bis 3.4549999999999 wird 3,45
## aus 3.4550000000001 bis 3.4599999999999 wird 3,46
##
## Außerdem werden Dezimalpunkte eingefügt und aus dem
## Dezimalpunkt wird ein Komma gemacht.
## z.B. aus 1234.56 wird 1.234,56 bei 2 Stellen
##
## Die Nachkommastellen werden mit 0 aufgefüllt wenn
## durch den Wert die angegebene Zahl nicht erreicht wird,
## z.B. aus 3.4 wird 3,400 bei 3 Stellen
##
## Wird aufgerufen mit
## $return = &RUNDEN($wert,$stellen);
## wobei $wert die zu rundende Zahl ist
## und $stellen die Anzahl der zu rundenden Nachkommastellen ist
##
## $return enthält dann den gerundeten Wert von $wert
## oder 0 bei Mißerfolg
##
my ($val,$dec) = @_;
return 0 if ((!defined $val) || (!defined $dec) || ($val=~ /[^-0-9\.]/) ||
($dec=~ /[^-0-9]/) || ($dec<0) || ($dec>10));
my $neg = 0;
if ($val<0) {$val=$val*-1;$neg = 1} # Vorzeichen raus sonst stimmt die
Rechnung nicht
$val = (($val + (0.5/(10**$dec)))*100)/100; # mathematisch aufrunden
my $res = int($val*(10**$dec))/(10**$dec); # Nachkommastellen abschneiden
$res =~ y/./,/; # ordentlich formatieren
my ($vor,$nach) = split(/,/,$res); # Vor-/Nach-Komma trennen
1 while $vor =~ s/(\d)(\d\d\d)\b/$1.$2/; # Tausenderpunkte
$nach = '' if !defined $nach; # wenn keine Nachkommastellen
while (length($nach)<$dec) {$nach.='0'} # ggfs. Nullen anhängen
$vor = '-'.$vor if $neg; # ggfs. Vorzeichen wieder rein
return $dec ? "$vor,$nach" : $vor; # ggfs. zusammenbauen
}
Gruß
> Nach DIN wird eine *exakte* 5 abgerundet, d.h. in diesem Beispiel muesste
> 1.345 zu 1.34 gerundet werden. Nur falls die 5 nicht exakt ist (d.h. es
gibt
> noch weitere Stellen ungleich 0) oder ihrerseits durch abrunden entstanden
> ist wird aufgerundet.
Welche DIN ist das? Wo finde ich die? Ich suche schon sehr lange etwas über
offizielle Rundungsregeln. Gilt dieses nur beim hier beschriebenen
kaufmännischen Runden oder überall? Hat es auch noch etwas mit einer "auf
gerade Zahl aufrunden" zu tun?
Hoffentlich kannst Du mir weiterhelfen.
Thomas Klein