Velocity Reviews > Perl > Rounding a float in Perl?

# Rounding a float in Perl?

jon rogers
Guest
Posts: n/a

 10-27-2003
Hi

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

(or some equivalent functionality)?

JR

Anno Siegel
Guest
Posts: n/a

 10-27-2003
Bernard El-Hagin <(E-Mail Removed)> wrote in comp.lang.perl.misc:
> jon rogers <(E-Mail Removed)> wrote in news:bnimib\$38\$(E-Mail Removed):
>
> > Hi
> >
> > 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

>
> [...]
>
>
> perldoc -q round

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

is twice as fast, and a compiled rounding function can be ten times
as fast.

Anno

Bart Lateur
Guest
Posts: n/a

 10-27-2003
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

sprintf

\$float = 1.234446732653623;
\$rounded = sprintf "%.5f", \$float;
print \$rounded;

However, that doesn't remove unnecessary trailing zeroes, or the decimal
point for integers.

--
Bart.

Philip Newton
Guest
Posts: n/a

 10-29-2003
On 27 Oct 2003 11:27:56 GMT, http://www.velocityreviews.com/forums/(E-Mail Removed)-berlin.de (Anno
Siegel) wrote:

> 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;
> }
>
> is twice as fast, and a compiled rounding function can be ten times
> as fast.

But that doesn't allow you to specify the number of decimal places to
round to, does it?

And I wonder whether, once you add the scaling necessary to support
that, it's still faster than sprintf.

Cheers,
Philip
--
Philip Newton <(E-Mail Removed)>
That really is my address; no need to remove anything to reply.
If you're not part of the solution, you're part of the precipitate.

Anno Siegel
Guest
Posts: n/a

 10-29-2003
Philip Newton <(E-Mail Removed)> wrote in comp.lang.perl.misc:
> On 27 Oct 2003 11:27:56 GMT, (E-Mail Removed)-berlin.de (Anno
> Siegel) wrote:
>
> > 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;
> > }
> >
> > is twice as fast, and a compiled rounding function can be ten times
> > as fast.

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

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

But we're approaching bean-counting territory here...

Anno

Bart Lateur
Guest
Posts: n/a

 10-29-2003
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".

--
Bart.

Anno Siegel
Guest
Posts: n/a

 10-29-2003
Bart Lateur <(E-Mail Removed)> 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).

Anno

Jürgen Exner
Guest
Posts: n/a

 10-29-2003
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".

But you don't use floats for currency calculations.

jue

Ilya Zakharevich
Guest
Posts: n/a

 10-29-2003
[A complimentary Cc of this posting was sent to
Anno Siegel
<(E-Mail Removed)-berlin.de>], who wrote in article <bno3ra\$1p7\$(E-Mail Removed)-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...

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.

Hope this helps,
Ilya

Anno Siegel
Guest
Posts: n/a

 10-31-2003
Ilya Zakharevich <(E-Mail Removed)> wrote in comp.lang.perl.misc:
> [A complimentary Cc of this posting was sent to
> Anno Siegel
> <(E-Mail Removed)-berlin.de>], who wrote in article
> <bno3ra\$1p7\$(E-Mail Removed)-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...

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

Anno

#!/usr/local/bin/perl
use strict; use warnings; \$| = 1;
use Benchmark qw( :all);

goto bench;

for ( -10 .. 10 ) {
my \$x = \$_ * 0.1;
my \$sp = sround( \$x);
my \$nin = nround( \$x);
my \$iin = cround( \$x);
print "\$x -> \$sp, \$nin, \$iin\n";
}
exit;

bench:

cmpthese( -5, {
sround => 'sround( rand( 100))',
nround => 'nround( rand( 100))',
iround => 'iround( rand( 100))',
});

################################################## #################

# Perl, scaling
sub nround {
my ( \$x, \$n) = @_;
my \$pow10 = 10**(\$n || 0);
\$x *= \$pow10;
my \$y = 0.5 + abs \$x;
my \$abs = int \$y;
\$abs -= \$abs % 2 if \$y == \$abs;
( \$x <=> 0) * \$abs/\$pow10;
}

# Perl, non-scaling
sub iround {
my \$x = shift;
my \$y = 0.5 + abs \$x;
my \$abs = int \$y;
\$abs -= \$abs % 2 if \$y == \$abs;
( \$x <=> 0) * \$abs;
}

# sprintf
sub sround {
my \$x = shift;
0 + sprintf '%.0f', \$x;
}