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

Hi,

This is driving me nuts :(

I'm trying to round a number like:

12314212412124124124.10623

..to:

12314212412124124124.11

I've done this a million times with sprintf - but it just refuses to work for me today :/

Example code I'm trying:

my $foo = "12314212412124124124.10623"; my $text = sprintf("%.2f", $foo); print $text;


Returns:

perl test.cgi
12314212412124123136.00

What am I doing wrong? Been a looong day - so I'm guessing its something stupid - but I can't see it.

TIA!

Andy

Replies are listed 'Best First'.
Re: Stupid sprintf question - decimals
by kennethk (Abbot) on Oct 12, 2010 at 15:08 UTC
    The fact that the digits near the end are changing on you should throw up a red flag in your mind. Consider the following case; the code

    #!/usr/bin/perl use strict; use warnings; printf "%.2f%s", "4212412124124124.10623", "\n"; printf "%.2f%s", "12412124124124.10623", "\n";

    outputs the result

    4212412124124124.00 12412124124124.11

    You are exceeding machine precision on your decimal. See What Every Computer Scientist Should Know About Floating-Point Arithmetic for background.

Re: Stupid sprintf question - decimals
by ikegami (Patriarch) on Oct 12, 2010 at 15:20 UTC
    It's not a problem with rounding so much as a problem storing the number in the first place. Double precision floats have roughly 16 decimal digits of precision.
    12314212412124124124.10623 (Your number) |------16------| 12314212412124123136.00 (The output)

    You'll need something that can support more precision, such as Math::BigFloat or build of Perl that supports quad precision floats.

Re: Stupid sprintf question - decimals
by Utilitarian (Vicar) on Oct 12, 2010 at 15:05 UTC
    Hi Andy,
    What does
    perl -e '$num=12314212412124124124.10623;print "initial:\t$num\n";prin +tf ("formatted:\t%f\n",$num);printf ("rounded:\t%.2f\n",$num);' initial: 1.23142124121241e+19 formatted: 12314212412124123136.000000 rounded: 12314212412124123136.00
    tell you?

    that's a very bignum and printf won't handle it

    #!/usr/bin/perl use strict; use warnings; use bignum; sub rounder{ my ($prec,$num)=@_; my $round=0.5 / (10**$prec); $num+=$round; $num=~ s/(\.\d{$prec})\d*$/$1/; return $num; } my$num=12314212412124124124.10623; print "initial:\t$num\n"; print "rounded:\t", rounder(2 ,$num),"\n"; __END__ initial: 12314212412124124124.10623 rounded: 12314212412124124124.11
    print "Good ",qw(night morning afternoon evening)[(localtime)[2]/6]," fellow monks."
      ...as an alternative, use precision():

      $ perl -Mbignum -le 'my $x = 12314212412124124124.10623; $x->precision +(-2); print $x;' 12314212412124124124.11
      ah thanks guys - didn't realise there was a limit with the size of number you could use ;) (that was only a simple test number)

      I've shorted it, and works fine now <G>

      Thanks again

      Andy
Re: Stupid sprintf question - decimals
by snape (Pilgrim) on Oct 12, 2010 at 16:18 UTC

    Probably this might help

    my $foo = "12314212412124124124.10623"; my $text = int(sprintf("%0.2f", $foo)); print $text,"\n";

    I think since the number is too huge that is why it is not able to round it off. Double Precision works for 15 digits of precision and a range of at least 1e-100 to 1e100. You can read about it here