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

Hi,

is there any way to round the result of a mathematical expression without the use of int() or printf().
Also is there an operator that is similiar to % that returns just the the pre-point-part of a division rather
than the past-point-part.

Replies are listed 'Best First'.
Re: Rounding without int() or printf()
by japhy (Canon) on Feb 26, 2001 at 21:48 UTC
    Rounding without mathematical operations will be far slower. Treating numbers like strings in order to round them is probably a dubious task. Use a mathematical approach:
    # $rounded = round($value, $places); sub round { my ($N,$P) = @_; my $pm = $N > 0 ? 1 : -1; return int($N * 10**$P + .5 * $pm) / 10**$P; }


    japhy -- Perl and Regex Hacker
Re: Rounding without int() or printf()
by davorg (Chancellor) on Feb 26, 2001 at 21:55 UTC

    The POSIX module contains functions called ceil and floor which return the first integer greater or less than a given number.

    #!/usr/bin/perl -w use strict; use POSIX qw(ceil floor); my @numbers = qw(1 1.2 1.5 1.7 -1.2 -1.5 -1.7); foreach (@numbers) { printf("x: %.1f: ceil(x): %d floor(x) %d\n", $_, ceil($_), floor($_)); }
    --
    <http://www.dave.org.uk>

    "Perl makes the fun jobs fun
    and the boring jobs bearable" - me

Re: Rounding without int() or printf()
by AgentM (Curate) on Feb 26, 2001 at 21:47 UTC
      use integer is interesting, but I wouldn't call that rounding (similar with ceil and floor). Certainly it depends on what your numbers represent, but if you have a set of values that should have a known sum, proper rounding works much better than truncation. On the other hand, if your numbers represent, say, the number of people that can fit in a vehicle, you definitely want integers, and definitely want truncation of the values, lest you risk truncation of the people when the erroneous result is tested ;-).

      It's also worth noting that it affects the definition of the binary % operator, in that you get the native C compiler version which may not behave as expected for negative values.

      --
      I'd like to be able to assign to an luser

Re: Rounding without int() or printf()
by Albannach (Monsignor) on Feb 26, 2001 at 21:46 UTC
    It might help to know why you have such a strange, seemingly arbitrarily-restrictive request, but you might want to try sprintf().

    --
    I'd like to be able to assign to an luser

      The rounding-part of my question was just asked out of sheer curiosity.

      The part about the alternative division op came to my mind since I had been programming a little bit of ol' fashioned PASCAL before
      and PASCAL does contain an operator (or function) like that.
(tye)Re: Rounding without int() or printf()
by tye (Sage) on Feb 26, 2001 at 22:03 UTC
    $num++ if $num =~ s#\.(\d*)## && "5" le $1;

    Though this "rounds" things like 1.23e14 to 1e14 !

            - tye (but my friends call me "Tye")
Re: Rounding without int() or printf()
by jeroenes (Priest) on Feb 27, 2001 at 11:55 UTC
    I feel obliged to mention Math::Round here.

    Jeroen
    "We are not alone"(FZ)

Re: Rounding without int() or printf()
by I0 (Priest) on Feb 27, 2001 at 00:52 UTC
    use POSIX; $round = floor($num + 0.5); #unless you need to round .5 to even
Re: Rounding without int() or printf()
by BrotherAde (Pilgrim) on Feb 27, 2001 at 02:47 UTC
    Here's a method which doesn't use anything but basic arithmetics. It works, but I consider it pretty much unusable due to speed-(or rather lack thereof)-considerations:
    sub round { my $temp=$_[0]; my $rounded=0; while ($temp>.5) { $temp--; $rounded++; } return $rounded; } print &round(23.9);
Re: Rounding without int() or printf()
by extremely (Priest) on Feb 27, 2001 at 03:46 UTC
    Well how about one answer to both your questions? =) OK, I lied, it is two answers...
    sub trunc { my $r = shift; return 0 if ! $r; my $s = $r + $r/abs($r); return $r % $s; } sub grr { my ($q, $d) = @_; return int( $q/$d); }

    And honestly, any language that implements a round function invisibly inplements a numerical truncate like "int()" if it doesn't do it explicitly. For instance, to pick a random language say "Perl" =), the '%' modulus forces both of it's arguments to int's before using them.

    --
    $you = new YOU;
    honk() if $you->love(perl)

Re: Rounding without int() or printf()
by dash2 (Hermit) on Feb 27, 2001 at 16:54 UTC
    You should be aware of what sort of rounding you are doing. I got into nasty trouble once confusing mathematician's rounding with accountancy rounding. Maths rounds .5 up or down, depending on whether the integer part is odd or even, in order to avoid statistical bias. Accountancy always rounds .5 up.

    I don't know if there is a module for accountancy rounding; I ended up using

    $toround =~ /\.(\d)/; if ($1 >= 5) { $toround+=.5 } $toround = int $toround;
    which is probably pretty fugly, but did the job.

    Update Duh, and it uses int(). Excuse my idiocy.
    Dave