Hirl: Auf- und abrunden

Kann mir vielleicht jemand einen einfachen Weg zeigen,wie ich  Kommazahlen, die ich durch Berechnungen in einem Perl-Programm erhalte,  auf eine bestimmte Stelle nach dem Komma auf- oder abrunden kann.

  1. Wie man kaufmännisch rundet ist mir leider nicht bekannt. Aber mit einem Trick geht es auch per int()-Befehl.

    $zahl = int($zahl + 0.5) - 0.5;

    Int() gibt ja nur Ganzzahlen aus, d.h. schneidet den Komma-Wert einfach ab. Wenn man vorher die Zahl + 0.5 rechnet und danach wieder um 0.5 reduziert, erzielt man genau das gleiche Ergebnis wie bei einer kaufmännischen Rundung.

    Gruß Benjamin

    1. Hallo Benjamin,

      Wie man kaufmännisch rundet ist mir leider nicht bekannt. Aber mit einem Trick geht es auch per int()-Befehl.

      $zahl = int($zahl + 0.5) - 0.5;

      Int() gibt ja nur Ganzzahlen aus, d.h. schneidet den Komma-Wert einfach ab. Wenn man vorher die Zahl + 0.5 rechnet und danach wieder um 0.5 reduziert, erzielt man genau das gleiche Ergebnis wie bei einer kaufmännischen Rundung.

      irgendetwas kann hier nicht stimmen:

      angenommen $zahl ist 10.3.
      $zahl + 0.5 ist dann 10.8
      int (10.8) ergibt 10
      10 - 0.5 ergibt 9.5

      daraus wuerde folgen, dass 10.3 gerundet 9.5 ergibt, und das kann ja nicht sein.

      Viele Gruesse

      Beate Mielke

    2. Wie Beate schon angemerkt hat, paßt

      $zahl = int($zahl + 0.5) - 0.5;

      wohl nicht ganz ...

      besser (aber noch immer nicht ideal) ist
      $zahl = int($zahl + 0.5);
      das ist dann kaufmännisches Runden

      Als Wort zum Sonntag noch ein Zitat aus "man perlfunc":
      <quote>
      int EXPR
      int
      Returns the integer portion of EXPR. If EXPR is omitted, uses $_. You should not use this function for rounding: one because it truncates towards 0, and two because machine representations of floating point numbers can sometimes produce counterintuitive results. For example, int(-6.725/0.025) produces -268 rather than the correct -269; that's because it's really more like -268.99999999999994315658 instead. Usually, the sprintf(), printf(), or the POSIX::floor and POSIX::ceil functions will serve you better than will int().
      </quote>
      Prägnanter kann man es nicht ausdrücken ;-)

      mit herzlichem RTFM
          K@rl

      1. Hallo K@rl

        Als Wort zum Sonntag noch ein Zitat aus "man perlfunc":
        <quote>
        int EXPR
        int
        Returns the integer portion of EXPR. If EXPR is omitted, uses $_. You should not use this function for rounding: one because it truncates towards 0, and two because machine representations of floating point numbers can sometimes produce counterintuitive results. For example, int(-6.725/0.025) produces -268 rather than the correct -269; that's because it's really more like -268.99999999999994315658 instead. Usually, the sprintf(), printf(), or the POSIX::floor and POSIX::ceil functions will serve you better than will int().
        </quote>
        Prägnanter kann man es nicht ausdrücken ;-)

        mit herzlichem RTFM

        Im Prinzip hast Du schon recht, nur war dies das falsche Beispiel.
        Denn in diesem 'fucking manual' steht zu floor nur folgendes:

        <cite POSIX>
        floor
             This is identical to the C function floor().
        </cite>

        Und was sagt mir das als _Nicht_ c-Programmierer bezüglich Funktionsparameter, Rückgabewert und Funktionsweise ???

        Grüsse
        Tom

        1. Im Prinzip hast Du schon recht, nur war dies das falsche Beispiel.
          Denn in diesem 'fucking manual' steht zu floor nur folgendes:

          <cite POSIX>
          floor
               This is identical to the C function floor().
          </cite>

          Und was sagt mir das als _Nicht_ c-Programmierer bezüglich Funktionsparameter, Rückgabewert und Funktionsweise ???

          ich tippe mal: Funktionsparameter eine Zahl und Rückgabe wert eine Zahl .. was anderes würde mich wundern;

          zur Funktionsweise: wenn Du eine U*x Maschine hast: "man floor" eingeben (.. oder isses "man3 floor"? - hab hier eine DOS Maschine).

          Ansonsten:

          <cite>
          Usually, the sprintf(), printf(), or the POSIX::floor and POSIX::ceil functions will serve you better
          </cite>

          Ther's more than one way to do it -> ich persönlich setze sprintf ein

        2. Hi Tom!

          Und was sagt mir das als _Nicht_ c-Programmierer bezüglich Funktionsparameter, Rückgabewert und Funktionsweise ???

          <CITE SOURCE="Microsoft Visual C++ 5.0 Runtime Library Reference">
              double floor(double x);
              Calculates the floor of a value.

          Function    Required Header     Compatibility
              floor       <math.h>            ANSI, Win 95, Win NT

          Return Value

          The floor function returns a floating-point value representing the largest integer that is less than or equal to x. There is no error return.

          Parameter

          x Floating-point value

          Example

          /* FLOOR.C: This example displays the largest integers
               * less than or equal to the floating-point values 2.8
               * and -2.8. It then shows the smallest integers greater
               * than or equal to 2.8 and -2.8.
               */

          #include <math.h>
              #include <stdio.h>

          void main( void )
              {
                 double y;

          y = floor( 2.8 );
                 printf( "The floor of 2.8 is %f\n", y );
                 y = floor( -2.8 );
                 printf( "The floor of -2.8 is %f\n", y );

          y = ceil( 2.8 );
                 printf( "The ceil of 2.8 is %f\n", y );
                 y = ceil( -2.8 );
                 printf( "The ceil of -2.8 is %f\n", y );
              }

          Output

          The floor of 2.8 is 2.000000
              The floor of -2.8 is -3.000000
              The ceil of 2.8 is 3.000000
              The ceil of -2.8 is -2.000000

          See Also ceil, fmod
          </CITE>

          Ist zwar eine Microsoft-Beschreibung, da als "Compatibility" jedoch ANSI angegeben ist, sollte die Bibliothek bei jedem Ansi-kompatiblen C genauso funktionieren.

          Calocybe

  2. Hallo Hirl

    Das ist doch in Perl kein Problem ...

    ... dachte ich, bis ich im Perl-Manual nach der Round-Funktion suchte und diese nicht fand. :-((

    Nun habe ich eine solche Funktion mal selbst programmiert und stelle Sie hier zur freien Verfügung:

    Funktion zum Runden in Perl

    sub round
    {
        my $value = shift;          # Wert, der gerundet werden soll
        my $precision = int(shift); # Anzahl Stellen nach dem Komma, auf die gerundet werden soll. Muss eine Ganzzahl sein.
                                    # Positive Ganzahlen stellen die Stellen hinter dem Komma dar,
                                    # negative Ganzzahlen die Anzahl der signifikanten Stellen vor dem Komma.

    # Speichert das Vorzeichen und setzt value auf den Absolutwert.
        my $sign = 1;
        if($value < 0)
            { $sign = -1; }
        $value = abs($value);

    # Berrechnet den Genauigkeitsfaktor
        my $pFactor = 10 ** $precision;
        
        # Rundet den Wert
        $value = int(($value * $pFactor) + 0.5) / $pFactor;
        
        # Berücksichtigt das ursprüngliche Vorzeichen
        $value *= $sign;
        
        return $value;
    }

    Hier der Output eines Test-Skript für diese Round-Funktion:

    Testausgabe der Funktion round(value,precision):

    Runden auf Ganzahl (precision=0):
    round(0.5,0) = 1
    round(0.51,0) = 1
    round(0.49,0) = 0
    round(-0.5,0) = -1
    round(-0.6,0) = -1
    round(-0.4,0) = 0
    round(0.0,0) = 0
    round(25.34,0) = 25
    round(-36.82,0) = -37

    Runden auf Nachkommastellen (precision>0):
    round(0.453852,1) = 0.5
    round(0.453852,2) = 0.45
    round(0.453852,3) = 0.454
    round(0.453852,4) = 0.4539
    round(0.453852,5) = 0.45385
    round(-15.2853,2) = -15.29
    round(2546.0127,1) = 2546
    round(0.758,5) = 0.758
    -> Beachte: fehlende Stellen nach dem Komma werden NICHT mit '0' aufgefüllt. Dazu müssen die sprint()- und sprintf()-Funktionen verwendet werden.

    Runden auf signifikante Stellen vor dem Komma (precision<0):
    round(28457,-1) = 28460
    round(28457,-2) = 28500
    round(28457,-3) = 28000
    round(28457,-4) = 30000
    round(-1473.25,-2) = -1500
    round(28457.035,-8) = 0
    -> Beachte: Das Runden auf mehr Stellen vor dem Komma als der Wert selber aufweist, führt zum Ergebnis '0'.
    Vielleicht finde ich noch ein Workaround, um dieses Problem elegant zu lösen.

    Ich hoffe, damit ein kleines Problem gelöst zu haben.

    Grüsse
    Tom

    PS an die Forumsauslese-Redaktion: Wäre das nicht etwas, das in die FA aufgenommen werden könnte?
    In welcher Form hättet Ihr den kleinen Beitrag denn gerne?

    1. Hallo

      PS an die Forumsauslese-Redaktion: Wäre das nicht etwas, das in die FA aufgenommen werden könnte?
      In welcher Form hättet Ihr den kleinen Beitrag denn gerne?

      Sorry, ich hab es beim durchstöbern übersehen, dass das Thema in der FA schon existiert.
      Trotzdem könnte man den Beitrag um die obenstehende round-Funktion ergänzen, da die Funktion mächtiger und die Behandlung von negativen Werten korrekt ist.

      Grüsse
      Tom