Zahlen runden mit Math::Round

| | Kommentare (2)

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
ein.

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

2 Kommentare

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

Jetzt kommentieren

Über diese Seite

Diese Seite enthält einen einen einzelnen Eintrag von Thomas Fahle vom 12.11.08 13:00.

Devel::Size - Wieviel Speicher belegt meine Datenstruktur? ist der vorherige Eintrag in diesem Blog.

Linksammlung: EPIC - Perl Plugin für Eclipse ist der nächste Eintrag in diesem Blog.

Aktuelle Einträge finden Sie auf der Startseite, alle Einträge in den Archiven.

Blog Roll

Powered by

Powered by Movable Type 5.2.10

Creative Commons-Lizenz

Creative Commons License
Dieses Weblog steht unter einer Creative Commons-Lizenz.