http://www.perlmonks.org?node_id=544606

tamaguchi has asked for the wisdom of the Perl Monks concerning the following question:

How do you do in the easyiest way to round of decimal numbers to the nearest integer? thank you for your help.

Replies are listed 'Best First'.
Re: Rounding off numbers
by Tanalis (Curate) on Apr 20, 2006 at 14:22 UTC
      <s>sprintf and printf no longer rounds sometime after Perl 5.8.8. It truncates. </s>

      EDIT: I think I may have some bad information, which was corrected later on. If a calculation is done which results in 2.4999999999, sprintf("%.2f",2.49999999) would "round" to 2.49 for some reason, which appears to be truncation, but is actually a different problem. You may not be able to reproduce the problem by typing in 2.4999999. 2.49999999 has to be the result of a calculation.

        It truncates.
        Does it?
        $ perl -wE 'printf "%.3f\n", .0009 + $];' 5.023
        ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
Re: Rounding off numbers
by swampyankee (Parson) on Apr 20, 2006 at 14:35 UTC

    Or, to avoid sprintf, you could use:

    $rounded = int($unrounded + 0.5);

    There are actually defined standards for rounding; to be absolutely pedantic, numbers which are exact odd multiples of ½ (i.e., (2n + 1)⁄/2) should round to the nearest odd number, so 4.5 and 5.5 should both round to 5


    added in edit

    salva's post reminded me that my fragment will only work for positive values of $unrounded. For negative values, one would have to subtract 0.5

    emc

    "Being forced to write comments actually improves code, because it is easier to fix a crock than to explain it. "
    —G. Steele
      swampyankee,
      There are actually defined standards for rounding; to be absolutely pedantic, numbers which are...

      Really? Where? I am not saying that because I don't believe you but because I am only familiar with rounding algorithms - not any standards. Do you have any reference material?

      I would have thought any standard would have been referenced in this rounding algorithm article or in the Wikipedia entry.

      Cheers - L~R

        Try this NIST pdf (although I seem to have reversed their rounding rules, which are "round to even" from the ones I remembered which were "round to odd". Ah, daily my memory more and more remembers a steel sieve).

        emc

        "Being forced to write comments actually improves code, because it is easier to fix a crock than to explain it. "
        —G. Steele
      (2*4.5+1)/2=5 (2*5.5+1)/2=6

      so I tried:

      (2*int(4.5)+1)/2=4.5 (2*int(5.5)+1)/2=5.5

      so then I tried:

      int(2*4.5+1)/2=5 int(2*5.5+1)/2=6

      how's that equation and reasoning again? please verify, thanks. and needing a standard rounding algorithm. I am unsure now what's really correct that you've given.

        Hello jmichae3, and welcome to the Monastery!

        As swampyankee said, int($x + 0.5) correctly rounds $x to an integer, provided that $x is non-negative.

        So, for example, if you have 2 * 4.5 and want to make sure this comes out to 9, use:

        19:27 >perl -wE "my $x = 2 * 4.5; my $y = int($x + 0.5); say $y;" 9 19:28 >

        This is useful, because for some values (and on some machines), a calculation like 2 * 4.5 might come out as 8.99999999998. But with the formula: add 0.5 and truncate, that’s OK now:

        19:28 >perl -wE "my $x = 8.99999999998; my $y = int($x + 0.5); say $y; +" 9 19:30 >

        Hope that helps,

        Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: Rounding off numbers
by salva (Canon) on Apr 20, 2006 at 14:29 UTC
    use POSIX 'floor'; sub round { my $x = shift; floor($x + 0.5); }

    You can use int instead of POSIX::floor if you don't need to round negative numbers. Anyway, read the docs for the int operator in perlfunc man page.

      .. though it's important to remember that simply casting a float to an int, thus:
      my $float = 2.744; my $int = int $float;
      results in the decimal part of the number simply being truncated, giving an integer value with the above example of 2, not 3, which is possibly not what's expected.

      Update: Although, of course, adding the 0.5 to the number solves the problem nicely. Didn't see that in the post until just now ..

Re: Rounding off numbers
by Roy Johnson (Monsignor) on Apr 20, 2006 at 17:05 UTC
Re: Rounding off numbers
by johngg (Canon) on Apr 20, 2006 at 15:15 UTC
    I knocked up a module, probably my first ever, to do rounding. I used POSIX::ceil() and POSIX::floor() to a recipe I saw in a C text book. Written before I knew about strict and warnings, I'm afraid; I'll have to revisit it one day.

    package Rounders; use Exporter; @ISA = ('Exporter'); @EXPORT = qw(rndZero rndPlaces); use Carp; use POSIX qw(ceil floor pow); sub rndZero { my($val) = shift; my $rounded = $val < 0 ? POSIX::ceil($val - 0.5) : POSIX::floor($val + 0.5); return $rounded; } sub rndPlaces { my($val, $places) = @_; my $rounded = rndZero($val * POSIX::pow(10.0, $places)) / POSIX::pow(10.0, $places); return $rounded; } 1;

    Calling like this

    $toNearest100 = rndPlaces(1234.56, -2);

    would result in $toNearest100 getting a value of 1200.

    Cheers,

    JohnGG