The FAQ answer is "use sprintf()", which is fine in most cases. It
must be said, however, that sprintf() is a slow function, and if a
lot of rounding is going on it can easily dominate the calculation.
Even a pure Perl rounding function, along the lines of

Advertisements

jon rogers wrote:
>Is there any good way to round a float into n decimals in Perl?
>
>I'd like to see
>
>round($float,5); # rounds $float to (at most) 5 decimal digits
>
>which would turn
>1.234446732653623
>into
>1.23445

No, it doesn't. I don't remember the last time I wanted to round to
anything but the nearest integer, but the objection is valid.
> And I wonder whether, once you add the scaling necessary to support
> that, it's still faster than sprintf.

It (i.e. my implementation on my machine) is still 44% faster than sprintf,
as opposed to 113% for the non-scaling version. Then again, it can also
round 1234 to 1000 for a negative "number of decimal places", something
sprintf doesn't do.

Anno Siegel wrote:
>> But that doesn't allow you to specify the number of decimal places to
>> round to, does it?
>
>No, it doesn't. I don't remember the last time I wanted to round to
>anything but the nearest integer, but the objection is valid.

Bart Lateur <> wrote in comp.lang.perl.misc:
> Anno Siegel wrote:
>
> >> But that doesn't allow you to specify the number of decimal places to
> >> round to, does it?
> >
> >No, it doesn't. I don't remember the last time I wanted to round to
> >anything but the nearest integer, but the objection is valid.
>
> Think "currency".

Oh, sure, it happens. Though, particularly with financial calculations,
an accepted technique is to first convert everything to cents (or whatever).

Bart Lateur wrote:
> Anno Siegel wrote:
>
>>> But that doesn't allow you to specify the number of decimal places
>>> to round to, does it?
>>
>> No, it doesn't. I don't remember the last time I wanted to round to
>> anything but the nearest integer, but the objection is valid.
>
> Think "currency".

[A complimentary Cc of this posting was sent to
Anno Siegel
<-berlin.de>], who wrote in article <bno3ra$1p7$-Berlin.DE>:
> It (i.e. my implementation on my machine) is still 44% faster than sprintf,
> as opposed to 113% for the non-scaling version. Then again, it can also
> round 1234 to 1000 for a negative "number of decimal places", something
> sprintf doesn't do.
>
> But we're approaching bean-counting territory here...

If so, that appears to be the case on more than one machine. I'm
getting consistent results (i.e. Perl rounding beats sprintf rounding)
on several machines. I'm appending the benchmarks i used for reference.

[A complimentary Cc of this posting was sent to
Anno Siegel
<-berlin.de>], who wrote in article <bntfci$gjv$-Berlin.DE>:
> > On my machine (EMX on 850MHz Athlon) your version takes 5.03 us per
> > iteration (when non-scaling). sprintf takes 0.15 us per iteration.
> > Apparently your CRT implementation is completely broken speedwise...
> > Enough said.
> If so, that appears to be the case on more than one machine. I'm
> getting consistent results (i.e. Perl rounding beats sprintf rounding)
> on several machines. I'm appending the benchmarks i used for reference.

My bad. My test had sprintf() constant-folded. After modifying it, I
get results similar to what you describe.

Which means: it makes sense to special-case several formats before
they are handled to

[A complimentary Cc of this posting was sent to
Anno Siegel
<-berlin.de>], who wrote in article <bnivfs$i76$-Berlin.DE>:
> The FAQ answer is "use sprintf()", which is fine in most cases. It
> must be said, however, that sprintf() is a slow function, and if a
> lot of rounding is going on it can easily dominate the calculation.
> Even a pure Perl rounding function, along the lines of
>
> sub round {
> my $x = shift;
> my $y = 0.5 + abs $x;
> my $abs = int $y;
> $abs -= $abs % 2 if $y == $abs;
> ($x <=> 0) * $abs;
> }

Today I sent a patch which sped up sprint "%.0f" 15x.

Hope this slightly compensates my goof with having a constant-folded
benchmark ;-),
Ilya

Ah... that's about as fast as it gets. Now we can promote the FAQ answer
to rounding in good conscience.
> Hope this slightly compensates my goof with having a constant-folded
> benchmark ;-),

Well, it happens. When Perl 5 was new, I presented a benchmark to p5p,
proving that an extensive patch to the % operator didn't cost any time
at all. Both sides of the benchmark where constant-folded. Larry had
to set me straight.

-berlin.de (Anno Siegel) wrote in message news:<bntfci$gjv$-Berlin.DE>...
Your rounding is faster, but it doesn't quite work, in the sense of
always getting the same result as sprintf *or* the mathematically
accurate result.

Roy Johnson <> wrote in comp.lang.perl.misc:
> -berlin.de (Anno Siegel) wrote in message
> news:<bntfci$gjv$-Berlin.DE>...
> Your rounding is faster, but it doesn't quite work, in the sense of
> always getting the same result as sprintf *or* the mathematically
> accurate result.

What is the mathematically accurate result of rounding 0.05 to one
decimal place? The problem is, there are two equally likely candidates,
and mathematics doesn't presume to make a decision. Mathematically,
the result isn't defined.
> nround(0.05, 1) yields 0, whereas sprintf('%.1f', 0.05) yields 0.1. Of
> course, sprintf('%.1f', 3.05) yields 3.0, and so does Nround.

Algorithms have to make a decision, and standards define how to make
it. I am a little surprised at what IEEE does here (assuming it *is*
IEEE), or rather, I would be surprised if I hadn't long ago given up
being surprised by numeric results.
> Here's one that works (in the sense of being mathematically accurate)
> for all the values I've tried, but it is only about half as fast as
> nround, or 3/4 as fast as sprintf.

Again, there is no "mathematically accurate" solution in the critical
case (where both possible values are equally far off). However, your
solution now differs from sprintf when rounding 0.5 to an integer:
sprintf says 0, stround says 1.

Hmm... I can't say that I like the mixture of arithmetic and text-
processing, though it may be said to be typical of Perl. If I had to
*prove* an implementation conforms to some standard, I'd prefer a numeric
solution, if possible one that corresponds step by step to the description
in the standard.

-berlin.de (Anno Siegel) wrote in message news:<bo8rm2$n4$-Berlin.DE>...
> What is the mathematically accurate result of rounding 0.05 to one
> decimal place?

Convention says it rounds up. Maybe that's not mathematics, per se.
Maybe it's not even a universal convention, but it's the only one I
ever heard.
> However, your solution now differs from sprintf when rounding 0.5 to
> an integer: sprintf says 0, stround says 1.

I'm actually happy with that, because it's consistent and
conventional. sprintf's inconsistent rounding is lamented in the FAQ.
> If I had to *prove* an implementation conforms to some standard, I'd
> prefer a numeric solution

Except for the fact that numeric representation is the problem. Using
the strings is the workaround. As an internal number, there may be no
such thing as exactly 3.005, but as a string, there is.

Guest

(Roy Johnson) wrote:
> -berlin.de (Anno Siegel) wrote in message
> news:<bo8rm2$n4$-Berlin.DE>...
> > What is the mathematically accurate result of rounding 0.05 to one
> > decimal place?
>
> Convention says it rounds up. Maybe that's not mathematics, per se.
> Maybe it's not even a universal convention, but it's the only one I
> ever heard.

Another popular (and better) convention is to round up if the preceding
digit is odd and down if the preceding digit is even, i.e. 0.05 -> 0.0,
while 0.15 -> 0.2.

[A complimentary Cc of this posting was sent to
Anno Siegel
<-berlin.de>], who wrote in article <bo7nm6$3qn$-Berlin.DE>:
> > Hope this slightly compensates my goof with having a constant-folded
> > benchmark ;-),
>
> Well, it happens.

The real problem is that I know that it happens, so this is the first
thing I check when *somebody else* posts a benchmark. Sigh....

Roy Johnson <> wrote in comp.lang.perl.misc:
> -berlin.de (Anno Siegel) wrote in message
> news:<bo8rm2$n4$-Berlin.DE>...
> > What is the mathematically accurate result of rounding 0.05 to one
> > decimal place?
>
> Convention says it rounds up. Maybe that's not mathematics, per se.
> Maybe it's not even a universal convention, but it's the only one I
> ever heard.

The convention has the disadvantage that it's biased. Positive numbers
will on average become larger and negatives become smaller.
> > However, your solution now differs from sprintf when rounding 0.5 to
> > an integer: sprintf says 0, stround says 1.
>
> I'm actually happy with that, because it's consistent and
> conventional. sprintf's inconsistent rounding is lamented in the FAQ.

It may look inconsistent, but there are reasons for that. Compilers
of mathematical tables have used it for centuries.
> > If I had to *prove* an implementation conforms to some standard, I'd
> > prefer a numeric solution
>
> Except for the fact that numeric representation is the problem. Using
> the strings is the workaround. As an internal number, there may be no
> such thing as exactly 3.005, but as a string, there is.

Numeric representation is a problem, but the purpose of rounding isn't
to show you the string you expect from looking at the (already rounded)
standard representation of the number. It must come up with a repre-
sentable approximation to the true rounded value.

Share This Page

Welcome to The Coding Forums!

Welcome to the Coding Forums, the place to chat about anything related to programming and coding languages.

Please join our friendly community by clicking the button below - it only takes a few seconds and is totally free. You'll be able to ask questions about coding or chat with the community and help others.
Sign up now!