Re: Rounding up in perl



On 2008-12-20 16:39, Tim Greer <tim@xxxxxxxxxxxxx> wrote:
Peter J. Holzer wrote:
As Ilya said, truncating is one of several modes of rounding.

Right. I am well aware of that, and I even said so as well before Ilya
replied.

It's not that int doesn't round, or that
isn't dependable, it just usually isn't the rounding function you
want.

And that is what I said previously, it's not probably want you want,
since it's intent is to truncate (even if that is a method used for
rounding),

We may have a language problem here. I wouldn't say "truncating is a
method used for rounding", but "truncating is a method of rounding". The
former implies that there is only one way of rounding, and truncating is
not rounding, but can be used to implement rounding. The latter implies
that there are many ways of rounding, and trucating is one of them.

and I think that it's not as dependable as other solutions,

Again, we may have a language problem. If I say a method is "not
dependable" I mean that it does give the expected result most of the
time, but sometimes it gives the wrong result, and the problem isn't
immediately apparent.

To borrow an example from a recent thread, replacing a symlink with

unlink($link) if -e $link;
symlink($target, $link);

is not dependable. It works almost all of the time, but there is a
possibility that another process creates $link between the time your
process has removed it and tries to recreate it - and unless you are
used to thinking about race conditions, you may not see that.

OTOH, if you do something like

$y = int($x) # round to nearest int

that's not a question of dependability. That will produce the wrong
answer for 50% of all possible values, and it is immediately apparent
from the definition of the int function, that it is the wrong function
to use in this case. (floor and ceil are of course, just as wrong).

Let's assume you want a function which rounds the way you learned in
primary school: Round to nearest integer, and break ties away from zero.

sub common_round_i { my ($x) = @_; return int($x); }

sub common_round_f { my ($x) = @_; return floor($x); }

sub common_round_c { my ($x) = @_; return ceil($x); }

sub common_round_s { my ($x) = @_; return sprintf("%.0f", $x); }

It is immediately clear that the first three implementations don't do
what you want. The first two round 0.9 down (instead of up) and
common_round_c rounds 0.1 up (instead of down).

common_round_s seems to do the right thing at the first glance:
It rounds 0.1 down, it rounds 0.9 up, it rounds 1.5 up. But it rounds
0.5 down (instead of up), and that is probably not immediately apparent
to someone who hasn't learned a bit about numerical methods. So you
could say that using sprintf is "not dependable" (for the problem you
want to solve - there are good reasons for sprintf working the way it
does and at that point you should probably consider the possibility that
"rounding the way you learned in primary school" may not be what you
really need), while the other ways are not only "not dependable", they
are clearly und utterly wrong.

However, you can use the int, floor, and ceil functions to implement
your rounding function:

sub common_round_i2 {
my ($x) = @_;
return int($x + ($x >= 0 ? 0.5 : -0.5));
}

sub common_round_f2 {
my ($x) = @_;
return $x >= 0 ? floor($x + 0.5) : -floor(-$x + 0.5);
}

sub common_round_c2 {
my ($x) = @_;
return $x >= 0 ? -ceil(-$x - 0.5) : ceil($x - 0.5);
}


All of these are correct (as per specification), and there is no
mathematical reason to prefer one over the others. But common_round_i2
is slightly shorter and doen't need any modules, so I'd prefer that from
a Perl programmer's view.


which I also listed -- which the docs themselves also warn against.

The warning in the documentation is highly confusing. Not really wrong,
but very misleading if you don't already know about these things (and
then you don't need the warning).

hp

.



Relevant Pages

  • Re: Rounding Dollar Amounts
    ... LineTaxExempt field is checked (meaning tax exempt), ... This works most of the time, but I have run into a few rounding errors. ... With tax exempt checked (and multiple lines) ... By "rounds wrong", I mean I ...
    (comp.databases.ms-access)
  • Re: How to round down to nearest 5 minutes, time calc?
    ... Your formula rounds to 15 mins, your subject says to 5 mins. ... The first totals cell shows total exact time, ... The complex rounding down formula I got ...
    (microsoft.public.excel.programming)
  • Re: Bug in Delphi SimpleRoundTo function?
    ... Ask any mathematician and you'll get the same answer: 0.5 rounds up. ... Banker's Rounding is a convenience to avoid either party ... the trap of using floating *binary* point numbers, ...
    (borland.public.delphi.non-technical)
  • Re: Format$(.5, "00") returns "00" on some systems, "01" on others?
    ... But here he is trying to use Format to do the rounding, ... It would be much better if he rounds the number first. ... Here is a good rounding function, it always rounds .5 to 1 ... >> you are trying to convert a fraction to no fraction. ...
    (microsoft.public.vb.general.discussion)
  • Re: What is wrong with this Date calculation?
    ... Clng will often get it wrong because it rounds down to the nearest integer if the decimal portion of the date value is less than 0.5 and it rounds up to the nearest integer if the decimal portion of the date value is greater than 0.5 (and a bankers rounding up or down if the decimal part is exactly 0.5). ... Private Sub Command1_Click ...
    (microsoft.public.vb.general.discussion)