Zahlen runden kann eine recht tückische Aufgabe sein.
Das CPAN-Modul Math::Round von Geoffrey Rommel vereinfacht diese Aufgabe erheblich.
Dieser Beitrag geht auf die Themen
- Auf Ganze Zahlen runden
- Auf Fließkommazahlen runden, z.B. Nachkommastellen
- Zum nächsten Vielfachen auf- oder abrunden, z.B. Hunderter
Auf Ganze Zahlen runden
Die Prozeduren round, round_even, round_odd und round_rand runden auf Ganzzahlen (Integer) auf bzw. ab.
- round LIST rundet zur nächsten Ganzzahl auf bzw. ab.
- round_even LIST rundet zur nächsten Ganzzahl auf bzw. ab. Zahlen, die in der Mitte zwischen zwei Ganzzahlen liegen, werden zur nächsten geraden Zahl gerundet.
- round_odd LIST rundet zur nächsten Ganzzahl auf bzw. ab. Zahlen, die in der Mitte zwischen zwei Ganzzahlen liegen, werden zur nächsten ungeraden Zahl gerundet.
- round_rand LIST rundet zur nächsten Ganzzahl auf bzw. ab. Zahlen, die in der Mitte zwischen zwei Ganzzahlen liegen, werden zufällig auf- bzw. abgerundet
Beispiel: Zur nächsten Ganzzahl auf- oder abrunden:
#!/usr/bin/perl use strict; use warnings; use Math::Round qw/round/; my @zahlen = qw /-2.5 -2.0 -1.5 -1.0 -0.5 0.0 0.5 1.0 1.5 2.0 2.5 125.3456 125.5678/; foreach my $zahl ( @zahlen ) { printf("%8s wird zu %8s gerundet\n", $zahl, round($zahl)); }
Das Programm erzeugt folgende Ausgabe:
-2.5 wird zu -3 gerundet -2.0 wird zu -2 gerundet -1.5 wird zu -2 gerundet -1.0 wird zu -1 gerundet -0.5 wird zu -1 gerundet 0.0 wird zu 0 gerundet 0.5 wird zu 1 gerundet 1.0 wird zu 1 gerundet 1.5 wird zu 2 gerundet 2.0 wird zu 2 gerundet 2.5 wird zu 3 gerundet 125.3456 wird zu 125 gerundet 125.5678 wird zu 126 gerundet
Beispiel: round_even
#!/usr/bin/perl use strict; use warnings; use Math::Round qw/round_even/; my @zahlen = qw /-2.5 -2.0 -1.5 -1.0 -0.5 0.0 0.5 1.0 1.5 2.0 2.5 125.3456 125.5678/; foreach my $zahl ( @zahlen ) { printf("%8s wird zu %8s gerundet\n", $zahl, round_even($zahl)); }
Das Programm erzeugt folgende Ausgabe:
-2.5 wird zu -2 gerundet -2.0 wird zu -2 gerundet -1.5 wird zu -2 gerundet -1.0 wird zu -1 gerundet -0.5 wird zu 0 gerundet 0.0 wird zu 0 gerundet 0.5 wird zu 0 gerundet 1.0 wird zu 1 gerundet 1.5 wird zu 2 gerundet 2.0 wird zu 2 gerundet 2.5 wird zu 2 gerundet 125.3456 wird zu 125 gerundet 125.5678 wird zu 126 gerundet
Beispiel: round_odd
#!/usr/bin/perl use strict; use warnings; use Math::Round qw/round_odd/; my @zahlen = qw /-2.5 -2.0 -1.5 -1.0 -0.5 0.0 0.5 1.0 1.5 2.0 2.5 125.3456 125.5678/; foreach my $zahl ( @zahlen ) { printf("%8s wird zu %8s gerundet\n", $zahl, round_odd($zahl)); }
Das Programm erzeugt folgende Ausgabe:
-2.5 wird zu -3 gerundet -2.0 wird zu -2 gerundet -1.5 wird zu -1 gerundet -1.0 wird zu -1 gerundet -0.5 wird zu -1 gerundet 0.0 wird zu 0 gerundet 0.5 wird zu 1 gerundet 1.0 wird zu 1 gerundet 1.5 wird zu 1 gerundet 2.0 wird zu 2 gerundet 2.5 wird zu 3 gerundet 125.3456 wird zu 125 gerundet 125.5678 wird zu 126 gerundet
Beispiel: round_rand
#!/usr/bin/perl use strict; use warnings; use Math::Round qw/round_rand/; # Messbereich (Anzahl der Messungen); my $von = 1; my $bis = 10_000; # Die Zahl, die gemessen/geprüft wird my $zahl = 2.5; # Zaehler fuer Anzahl der Messungen my $anzahl_messungen = 0; # Container fuer die Messergebnisse my %messergebnis = (); for ( $von .. $bis ) { my $gerundet = round_rand($zahl); $messergebnis{$gerundet}++; $anzahl_messungen++; } my @messwerte = keys %messergebnis; foreach my $messwert (@messwerte) { print "$zahl wurde $messergebnis{$messwert} mal zu $messwert gerundet.\n"; print "Das entspricht ", $messergebnis{$messwert} / $anzahl_messungen * 100 , "%.\n"; }
Das Programm erzeugt folgende Ausgabe:
2.5 wurde 5044 mal zu 3 gerundet. Das entspricht 50.44%. 2.5 wurde 4956 mal zu 2 gerundet. Das entspricht 49.56%.
Runden auf Ganzzahlen im Vergleich
Das folgende Beispiel erstellt eine kleine tabellarische Übersicht, die den Vergleich der vorgestellten Prozeduren vereinfachen soll.
#!/usr/bin/perl use strict; use warnings; use Math::Round qw/round round_even round_odd round_rand/; my @zahlen = qw /-2.5 -2.0 -1.5 -1.0 -0.5 0.0 0.5 1.0 1.5 2.0 2.5 /; # Format für printf my $format = '%6s %6s %10s %10s %10s'; printf("$format\n", 'Zahl', 'round', 'round_even', 'round_odd', 'round_rand'); foreach my $zahl ( @zahlen ) { printf("$format\n", $zahl, round($zahl), round_even($zahl), round_odd($zahl), round_rand($zahl) ); }
Das Programm erzeugt folgende Ausgabe:
Zahl round round_even round_odd round_rand -2.5 -3 -2 -3 -3 -2.0 -2 -2 -2 -2 -1.5 -2 -2 -1 -2 -1.0 -1 -1 -1 -1 -0.5 -1 0 -1 0 0.0 0 0 0 0 0.5 1 0 1 1 1.0 1 1 1 1 1.5 2 2 1 2 2.0 2 2 2 2 2.5 3 2 3 2
Auf Fließkommazahlen runden
Hier bietet sich nearest(TARGET, LIST) an. nearest rundet zum Vielfachen von TARGET auf bzw. ab.
Beispiel: Auf eine bzw. zwei Nachkommastellen runden
#!/usr/bin/perl use strict; use warnings; use Math::Round qw/nearest/; my @zahlen = qw /-2.5 -2.0 -1.5 -1.0 -0.5 0.0 0.5 1.0 1.5 2.0 2.5 125.3456 125.5678/; my $format = '%8s %8s %8s'; printf("$format\n", 'Zahl', 'Eine NK', 'Zwei NK' ); foreach my $zahl ( @zahlen ) { # Eine Nachkommastelle (0.1) # Zwei Nachkommastellen (0.01) printf("$format\n", $zahl, nearest('0.1',$zahl), nearest('0.01',$zahl) ); }
Das Programm erzeugt folgende Ausgabe:
Zahl Eine NK Zwei NK -2.5 -2.5 -2.5 -2.0 -2 -2 -1.5 -1.5 -1.5 -1.0 -1 -1 -0.5 -0.5 -0.5 0.0 0 0 0.5 0.5 0.5 1.0 1 1 1.5 1.5 1.5 2.0 2 2 2.5 2.5 2.5 125.3456 125.3 125.35 125.5678 125.6 125.57
Zum nächsten Vielfachen auf- oder abrunden
Die beiden Prozeduren nlowmult und nhimult runden zum nächsten kleineren bzw. größerem Vielfachen ab bzw. auf.
- nlowmult TARGET, LIST rundet zum nächsten kleineren Vielfachen ab.
- nhimult TARGET, LIST rundet zum nächsten größeren Vielfachen auf.
Beispiel: Auf volle 100er auf- bzw. abrunden.
#!/usr/bin/perl use strict; use warnings; use Math::Round qw/nlowmult nhimult/; my @zahlen = qw/ 126 176/; # Auf volle 100er auf- bzw. abrunden my $target = 100; my $format = '%6s %10s %10s'; printf("$format\n", 'Zahl', 'nlowmult', 'nhimult'); foreach my $zahl (@zahlen) { printf("$format\n", $zahl, nlowmult($target,$zahl), nhimult($target,$zahl) ); }
Das Programm erzeugt folgende Ausgabe:
Zahl nlowmult nhimult 126 100 200 176 100 200
Das funktioniert auch mit Vielfachen von Fließkommazahlen. Probieren Sie es einfach mal aus.
Siehe auch
- Math::Round
- Math::SigFigs
- Math::BigInt
- Wikipedia: Rundung
- perldoc: sprintf
- perldoc: printf
- perldoc: Posix
- Perl FAQ 4.13 - Does perl have a round function? What about ceil() and floor()?
- PerlCommunityWiki » Wissensbasis » PerlTutorialKapitel5
- Perlmonks: How do I round a number?
- Perlmonks: How do I round up a number?
Wozu braucht man round_odd() bzw. round_even()? Ich meine, was sind Anwendungsfälle dafür?
Von round_rand() will ich mal gar nicht reden...
Viel interessanter finde ich nearest(), damit kann man z. B. Währungsbeträge runden:
nearest(0.01, $euro) - rundet auf zwei Nachkommastellen
nearest(1000, $euro) - rundet auf volle Tausender
Uwe
Hallo Uwe,
erwischt; ich verwende eigentlich auch nur nearest() um Währungen zu runden, das ist besser als sprintf("%.2f", ...).
Mir geht es in diesem Beitrag mehr darum darzustellen, dass es verschiedene Rundungsverfahren gibt und man diese auch in Perl sehr einfach anwenden kann.
Für die Rundung im Computer gibt es mehrere spezielle Rundungsverfahren, die alle eine gewisse Verzerrung (aka Fehler) aufweisen. Je nach akzeptiertem Fehler für die Rundung wählt man eines der erwähnten Rundungsverfahren. Siehe dazu http://de.wikipedia.org/wiki/Rundung#Rundung_im_Computer.
Thomas