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

perl -e 'use strict; use warnings; my @num = (3.95,4.95,5.95,8.95,8.94 +,8.96,9.95,9.96,9.97,9.94,10.08); foreach (@num){ my $num = $_ *100; print "$num\t"; my $tmp = sprintf("%010d", $num); print "$tmp\n"; }' 395 0000000395 495 0000000495 595 0000000595 895 0000000894 894 0000000894 896 0000000896 995 0000000994 996 0000000996 997 0000000997 994 0000000994 1008 0000001008

I was testing and found this. Why does this happen ?

Replies are listed 'Best First'.
Re: sprintf values
by Ratazong (Monsignor) on Apr 07, 2010 at 06:59 UTC
    Just assuming you are wondering about the following line:

    895 0000000894

    Floating point arithmetic isn't precise (or too precise, depending on the way you see it ;-) due to the way floating-point-values are stored internally.

    You might want to check the following node (and the whole thread): Re: Simple math gone wrong.

    8.95 * 100 will probably result internally to 894.9999999 - and if you print that, you'll get 894. Think about rounding the result before sprintf-ing it.

    HTH, Rata
Re: sprintf values
by Anonymous Monk on Apr 07, 2010 at 07:00 UTC
Re: sprintf values
by cdarke (Prior) on Apr 07, 2010 at 08:26 UTC
    Mixing integers and floating point is always problematic, the following illustrates:
    use strict; use warnings; my @num = (3.95,4.95,5.95,8.95,8.94,8.96,9.95,9.96,9.97,9.94,10.08); foreach (@num){ my $num = $_ *100; printf ("%d\t%010d\t%011.4f\n", $num, $num, $num); } 395 0000000395 000395.0000 495 0000000495 000495.0000 595 0000000595 000595.0000 894 0000000894 000895.0000 894 0000000894 000894.0000 896 0000000896 000896.0000 994 0000000994 000995.0000 996 0000000996 000996.0000 997 0000000997 000997.0000 994 0000000994 000994.0000 1008 0000001008 001008.0000

    Update: I just noticed I got slightly different results to you, which only goes to show how untrustworthy conversions are. I am probably running on different hardware, operating system, perl version, and C runtime library to you.
      ...and C runtime library

      FWIW, the C runtime library shouldn't matter here, as Perl has its own "printf"-like formatting routine ( Perl_sv_vcatpvfn() in sv.c, in case you're interested ).

        I think sv_vcatpvfn can or does use the C runtime to format floats. Even if it doesn't, the C runtime is used to create the floats in the first place, so it definitely matters.
Re: sprintf values
by ikegami (Patriarch) on Apr 07, 2010 at 14:52 UTC

    95/100 is a periodic number in binary just like 1/3 is a periodic number in decimal. Storing it as a float would require infinite storage, so the number isn't stored exactly.

    You need to round the number (%010.f) instead of truncating it (%010d).

Re: sprintf values
by stefbv (Priest) on Apr 07, 2010 at 08:24 UTC

    Note that converting to string will give the expected results.

    my $tmp = sprintf("%010s", $num);
    ... 895 0000000895 894 0000000894 ...

    Stefan