Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

Rounding of a number...

by mkenney (Beadle)
on Dec 27, 2004 at 01:21 UTC ( [id://417497]=perlquestion: print w/replies, xml ) Need Help??

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

I'm current using the following command to take a yearly amount and convert it to a weekly amount:

sprintf("%5.2f",$yearlyamount/52)

The problem is that it may round up such as 10.666 becomes 10.67. It needs to always round down so that 10.666 becomes 10.66. Any suggestions?

Mark

Replies are listed 'Best First'.
Re: Rounding of a number...
by NetWallah (Canon) on Dec 27, 2004 at 04:59 UTC
    The politically and mathematically correct way to do this is to use POSIX floor().
    use POSIX; my $y=523.4; printf('%7.2f',floor($y*100/52)/100); --Output--- 10.06
    The VALLUE that prints as 10.06 is 10.06538.

        ..."I don't know what the facts are but somebody's certainly going to sit down with him and find out what he knows that they may not know, and make sure he knows what they know that he may not know, and that's a good thing. I think it's a very constructive exchange," --Donald Rumsfeld

      In case anyone is wondering why floor() and not int(), it depends on your definition of "rounding" -- int() always rounds towards zero. floor() always rounds down to the next integer that is less than or equal to the number being rounded. This difference is important for negative numbers. E.g.:

      $ perl -le 'print int(5.45)' 5 $ perl -le 'print int(-5.45)' -5 $ perl -MPOSIX -le 'print floor(5.45)' 5 $ perl -MPOSIX -le 'print floor(-5.45)' -6

      -xdg

      Code posted by xdg on PerlMonks is public domain. It has no warranties, express or implied. Posted code may not have been tested. Use at your own risk.

Re: Rounding of a number...
by ysth (Canon) on Dec 27, 2004 at 01:38 UTC
    sprintf("%5.2f", int($yearlyamount/52*100)/100);
Re: Rounding of a number...
by steves (Curate) on Dec 27, 2004 at 01:42 UTC

    One way is to just drop the trailing digits:

    my $x = $yearlyamount / 52; $x =~ s/(\.\d\d)\d*$/$1/;
Re: Rounding of a number...
by Gilimanjaro (Hermit) on Dec 27, 2004 at 12:00 UTC
    In the spirit of TIMTOWDI:
    sprint("%5.2f",$yearlyamount/52 - 0.005)
      For my machine, it will give the wrong answer for any time $yearlyamount equals k * 13, for k at least 9. This is because 52 is 4 * 13, and hence the division by 52 gives the exact answer, and subtracting 0.005 (which cannot be represented exactly in binary) from it causes %f to round it down to the next decimal. For instance, 117 / 52 - 0.005, on my computer with my Perl (5.8.6, with longdoubles and 64bitints) is about 2.244999999999999999895916591441391574335284531116485595703125. Just a tiny, tiny bit below 2.245, but that's enough to give the answer 2.24, instead of 2.25.

      Doing arithmetic with reals is very tricky, and it's therefore better to use a good module. POSIX.pm for instance, with its floor method.

Re: Rounding of a number...
by legato (Monk) on Dec 27, 2004 at 15:36 UTC

    Here's another way to approach it:

    sub trunc { my ($float, $precision) = @_[0..1]; my @comp = split /\./, $float; chop $comp[1] while length($comp[1]) > $precision; #trim $comp[1].='0' for (length($comp[1])..$precision-1); #pad return "$comp[0].$comp[1]"; } printf ("%5.2f", trunc($yearlyamount/52,2));

    This will, of course, fail utterly if you pass in anything less than pristine values. I leave data validation and error handling as an exercise to whatever masochist chooses this route. Of course, you could also implement it in this insane manner:

    $weekly = int(($yearlyamount/52)*100); $weekly = s,\d{2}$,\.$&,; printf ("%5.2f", $weekly);

    As a last resort, you could always:

    $weekly = sprintf("%.3", $yearlyamount/52); chop($weekly); printf "%5.2", $weekly;

    Anima Legato
    .oO all things connect through the motion of the mind

      As a last resort, you could always:

      weekly = sprintf("%.3", $yearlyamount/52); chop($weekly); printf "%5.2", $weekly;
      Except that it will produce wrong values every now and then. It will produce a wrong value whenever $yearlyamount/52 is less than 0.0005 less than a whole number - but still less than said whole number. This causes the "%.3f" rounding to produce a ".000" number, of which the last 0 will be chopped. The final result will be a ".00" number. But it should have been a ".99" number.
      use POSIX "floor"; my $yearlyamount = 5199.98; my $weekly1 = sprintf("%.3f", $yearlyamount/52); chop($weekly1); my $weekly2 = floor(100*5199.98/52)/100; printf("%5.2f %5.2f\n", $weekly1, $weekly2); __END__ 100.00 99.99

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others sharing their wisdom with the Monastery: (2)
As of 2024-04-26 00:37 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found