Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

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

by awohld (Hermit)
on Oct 24, 2007 at 18:23 UTC ( [id://646956]=perlquestion: print w/replies, xml ) Need Help??

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

I have a number where I need to round down to one decimal place and it needs to be either ".5" or ".0".

I know this looks rediculously simple, but I don't see an easy solution to it. I looked at Math::BigFloat but it doesn't look like it can do this.

Below is my try but I can't even get the split to work, what's wrong with that?
#!/usr/bin/perl -w use strict; my $num = 5.8687; my ( $int, $float ) = split '.', $num; #$float = 5 if $float > ?; #$float = 0 if $float < ?; # example should print '5.5' print $int . '.' . $float . "\n";

Replies are listed 'Best First'.
Re: Round down to '.5' or '.0'
by gamache (Friar) on Oct 24, 2007 at 18:29 UTC
    How about:
    my $rounded = (int $num*2)/2;

      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. :)
          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

      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 );

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

Re: Round down to '.5' or '.0'
by moritz (Cardinal) on Oct 24, 2007 at 18:30 UTC
    There's an easy method:
    sub round_to_halves { return 0.5 * (int(2*$_[0])); } my $num = 1.6; print round_to_halves($num), "\n";
      Hell, why stop there?
      sub round_to_nths { my ($num, $n) = @_; (int $num*$n)/$n }
      Now you and me can reuse our rounding code all day, giggling as the split-based solution chokes on a well-placed $num = '123E-1'...
Re: Round down to '.5' or '.0'
by toolic (Bishop) on Oct 24, 2007 at 18:32 UTC
    split is not working the way you expect it to in your code because the first argument to split is a regular expression. Since "." is a special character in a regex, it must be escaped. I think this does what you expect:
    my ( $int, $float ) = split /\./, $num;

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://646956]
Approved by McDarren
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others exploiting the Monastery: (6)
As of 2024-04-23 18:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found