in reply to Round down to '.5' or '.0'

How about:
my $rounded = (int $num*2)/2;

Replies are listed 'Best First'.
Re^2: Round down to '.5' or '.0'
by ikegami (Patriarch) on Oct 24, 2007 at 18:50 UTC

    The best part is that *2 and /2 are lossless operations on floats.

    >perl -le"$,=' '; $x=.1; print map /(.)(.{11})(.*)/, unpack 'B*', reve +rse pack 'd', $x/=2 for 1..5;" 0 01111111010 1001100110011001100110011001100110011001100110011010 0 01111111001 1001100110011001100110011001100110011001100110011010 0 01111111000 1001100110011001100110011001100110011001100110011010 0 01111110111 1001100110011001100110011001100110011001100110011010 0 01111110110 1001100110011001100110011001100110011001100110011010 - ----------- ---------------------------------------------------- S Exponent Mantissa

    Precision already loss is not recuperated, of course.

    my $n; $n += 0.1 for 1..10; # $n = 0.1 * 10 = 1 ...ish my $r = int($n*2)/2; print("round($n) = $r\n"); # round(1) = 0.5 print("cause it's really doing\n"); # cause it's really doing printf("round(%.16e)\n", $n); # round(9.9999999999999989e-001)
      I was wondering whether mult/div by powers of 2 would be translated to add/sub on the binary exponent... I'm not sure your example just showed me, but I trust you. :)

        Added examples to my earlier post for you.

        A reply falls below the community's threshold of quality. You may see it by logging in.
      You can't be sure. i remember i saw a base16 floating point representation. in this case *2 and /2 are lossy.

      i prefer to say that everything is at risk of being lossy with floats.

      Oha

Re^2: Round down to '.5' or '.0'
by awohld (Hermit) on Oct 24, 2007 at 20:06 UTC
    Conversely, is there another trick to do the same but round up?
      use POSIX qw( ceil ); my $rounded = ceil($num*2)/2;

      Update: Oops, the above didn't work for negative numbers.

      use POSIX qw( ceil ); my $rounded = ($num>=0 ? +1 : -1) * ceil(abs($num)*2)/2;

      or

      use POSIX qw( ceil floor ); my $rounded = ($num >= 0 ? ceil($num*2)/2 : floor($num*2)/2 );
Re^2: Round down to '.5' or '.0'
by Nkuvu (Priest) on Oct 25, 2007 at 19:33 UTC

    For some reason I was under the impression that the int function was doing rounding rather than truncating, so took a quick look at perldoc -f int, which mentioned that you should use POSIX::floor() rather than int. And sure enough, the code snippet above provides what I'd consider to be incorrect results for negative values. The OP doesn't mention if the input values will ever be negative, but consider the following:

    #!/usr/bin/perl use strict; use warnings; use POSIX; my $num = -1.2; my $rounded_pos = (POSIX::floor($num*2))/2; my $rounded_int = (int $num*2)/2; printf "Rounded is %.1f for %f using POSIX\n", $rounded_pos, $num; printf "Rounded is %.1f for %f using int\n", $rounded_int, $num; __END__ Output: Rounded is -1.5 for -1.200000 using POSIX Rounded is -1.0 for -1.200000 using int

    Simple change, and seems to be more robust. (Added: Although I may just be misinterpreting "rounding down" -- I think "down" is "in the negative direction" as opposed to "closer to zero". Hmm.)