http://www.perlmonks.org?node_id=991469

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

Greetings everyone

I am trying to figure out which of the multiple rounding techniques is used by perl's (and I suspect C) printf. I can not find anything that matches on the interwebs. Can anyone explain in detail the output of the following oneliner:

perl -e 'printf "%s => %.1f\n", ("0.${_}5") x 2 for (0..9)' 0.05 => 0.1 0.15 => 0.1 <-- this pair precludes even/odd 0.25 => 0.2 <-- rounding as explanation 0.35 => 0.3 0.45 => 0.5 <-- looks like the threshold of down/up rounding behavior 0.55 => 0.6 0.65 => 0.7 0.75 => 0.8 0.85 => 0.8 <-- except not quite :( 0.95 => 0.9

Replies are listed 'Best First'.
Re: Funny sprintf rounding - how does it work?
by Athanasius (Archbishop) on Sep 03, 2012 at 16:55 UTC

    As one would expect?

    2:51 >perl -e "printf qq[%s => %.20f => %.1f\n], (qq[0.${_}5]) x 3 fo +r (0..9)" 0.05 => 0.05000000000000000300 => 0.1 0.15 => 0.14999999999999999000 => 0.1 0.25 => 0.25000000000000000000 => 0.3 0.35 => 0.34999999999999998000 => 0.3 0.45 => 0.45000000000000001000 => 0.5 0.55 => 0.55000000000000004000 => 0.6 0.65 => 0.65000000000000002000 => 0.7 0.75 => 0.75000000000000000000 => 0.8 0.85 => 0.84999999999999998000 => 0.8 0.95 => 0.94999999999999996000 => 0.9

    :-)

    Athanasius <°(((><contra mundum

      Gah! Such a simple and straightforward way to demonstrate this ;) Thanks!
Re: F***ing sprintf rounding - how does it work?
by choroba (Cardinal) on Sep 03, 2012 at 16:40 UTC
Re: Fucking sprintf rounding - how does it work?
by daxim (Curate) on Sep 03, 2012 at 16:38 UTC
    round towards even, and for me, 0.15 => 0.2.

    In the cases where your test program deviates from the expected value, it's just the usual floating point inaccuracy bullshit. I guess sprintf %f operates on NV/numbers.

      Could you please get the output of this on your CPU?
        Certainly.
        $ perl -e'printf qq[%s => %.68f => %.1f\n], (qq[0.${_}5]) x 3 for (0.. +9)' 0.05 => 0.050000000000000000000677626357803440271254658000543713569641 +11328125 => 0.1 0.15 => 0.150000000000000000005421010862427522170037264004349708557128 +90625000 => 0.2 0.25 => 0.250000000000000000000000000000000000000000000000000000000000 +00000000 => 0.2 0.35 => 0.349999999999999999994578989137572477829962735995650291442871 +09375000 => 0.3 0.45 => 0.449999999999999999989157978275144955659925471991300582885742 +18750000 => 0.4 0.55 => 0.550000000000000000010842021724855044340074528008699417114257 +81250000 => 0.6 0.65 => 0.649999999999999999978315956550289911319850943982601165771484 +37500000 => 0.6 0.75 => 0.750000000000000000000000000000000000000000000000000000000000 +00000000 => 0.8 0.85 => 0.850000000000000000021684043449710088680149056017398834228515 +62500000 => 0.9 0.95 => 0.949999999999999999989157978275144955659925471991300582885742 +18750000 => 0.9

        $ perl -V
Re: F***ing sprintf rounding - how does it work?
by swampyankee (Parson) on Sep 04, 2012 at 01:08 UTC

    There are actually standards regarding how rounding should be done, e.g. http://en.wikipedia.org/wiki/IEEE_floating_point#Rounding_rules (which is probably not universally followed) and ISO 717-1:1996. On the other hand, since floating point numbers are not real numbers (they're a subset of rational numbers), there will be times when sprintf will round the value it's given correctly, but the value that it gets is not correct, depending on how well the floating point library is written (some are much better than others) and the details of the computations being done

    I've had to deal with hand-rolled rounding solutions (so that rounded numbers would add up to an integral value). You may have to roll your own rounding subroutine if you've got specific requirements.


    Information about American English usage here and here. Floating point issues? Please read this before posting. — emc

Re: Fishing sprintf rounding - how does it work?
by Anonymous Monk on Sep 03, 2012 at 17:01 UTC
Re: F***ing sprintf rounding - how does it work?
by swampyankee (Parson) on Sep 04, 2012 at 14:48 UTC

    To investigate your system's floating point behavior, try http://www.netlib.org/paranoia/paranoia.c. You'll have to compile and link it, ideally with the same floating point library as used to compile perl on your system.


    Information about American English usage here and here. Floating point issues? Please read this before posting. — emc