Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number

Rounding a number using (s)printf

by the_slycer (Chaplain)
on Jan 19, 2005 at 21:59 UTC ( #423519=perlquestion: print w/replies, xml ) Need Help??

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

Hi.. I've run into a bit of whackiness that I'm at a loss to explain, I've tried this on 3 different machines (all running some flavor of linux), and the behaviour repeats. Perhaps I'm incorrect in my use of printf, but I've found nothing indicating this..

I'm attempting to round a number to 2 decimal places:
my (@numbers) = qw( 0.256 0.255 0.254 ); printf("%0.2f\n", $_) foreach @numbers; printf("%0.2f\n", 1.255);
I'd expect results like:
0.26 0.26 0.25 1.26
But what I'm seeing are results like:
0.26 0.26 0.25 1.25
Notice the 1.25 vs 1.26 that I'd expect..

As I said, I'm confused.. feel free to smite me down if I've pulled some kind of noob mistake.

Replies are listed 'Best First'.
Re: Rounding a number using (s)printf
by dave_the_m (Monsignor) on Jan 19, 2005 at 22:26 UTC
    0.255 and 1.255 are not exactly representable in base-2 floating point:
    $ perl -we 'printf "%.20f\n", 0.255' 0.25500000000000000444 $ perl -we 'printf "%.20f\n", 1.255' 1.25499999999999989342
    when the internal represenations of these two numbers are then rounded to 2 decimal places, one rounds up, the other down.


Re: Rounding a number using (s)printf
by borisz (Canon) on Jan 19, 2005 at 22:36 UTC
    Floating point numbers are not exactly represented.
    perl -e 'printf "%.18f", 1.255' __OUTPUT__ 1.254999999999999893
    so 1.25 is the correct result.
Re: Rounding a number using (s)printf
by data64 (Chaplain) on Jan 20, 2005 at 03:56 UTC
Re: Rounding a number using (s)printf
by hsinclai (Deacon) on Jan 19, 2005 at 22:31 UTC
    Does leaving the 0 preceding the decimal point out of the formatting directive change anything?
    printf("%.2f\n", 1.255);

Re: Rounding a number using (s)printf
by duff (Parson) on Jan 20, 2005 at 00:38 UTC

    It don't think it has anything to do with how the numbers are represented in floating point. I think what you're seeing is a result of sprintf() following IEEE rounding semantics. It's something like even least significant digits round up at the half-way mark and odd round down at the half-way mark.

    Search google for IEEE rounding semantics and I'm sure you'll find a better reference than I.

    Update: doh! There's even a mention in perldoc -q round

      You mean bankers rounding? That's not what's happening here. As you said yourself, the least significant digits play a role here. But the difference between 0.255 and 1.255 lies is the most significant digit.
      Did you try it? It has everything to do with how numbers are represented in floating point. There are numbers that can be exactly represented in floating point where the rounding is ambiguous, e.g. printf "%.1f", $_ for .25, .75, and a round-to-even-last-digit rule could apply, but in fact perl relies on C's printf(), and the SUSv3 standard says only "The low-order digit shall be rounded in an implementation-defined manner." Depending on how you interpret "rounded" in that sentence, you may not even be able to count on it rounding .24 to ".2".

      In point of fact, I don't know of any system that fails to round at all, but do know of some that do not consistently either apply or fail to apply a round-to-even-last-digit rule.

Re: Rounding a number using (s)printf
by nite_man (Deacon) on Jan 20, 2005 at 08:50 UTC

    This is a mathematical rule of rounding of numbers: if digit before last visible digit is greater than 5 last digit is increased by 1, otherwise the digit saves its value.

    So, 0.256 ~ 0.26, 0.255 ~ 0.25, 0.254 ~ 0.25. This is correct results.

    Michael Stepanov aka nite_man

    It's only my opinion and it doesn't have pretensions of absoluteness!

      Could you please first to read the entire question before babbling your response?

      First of all, you're wrong. The OP expected the results for 0.256, 0.255 and 0.254 to be 0.26, 0.26 and 0.25. And lo and behold, they were 0.26, 0.26 and 0.25. Because everyone learns in primary school that if the part we truncate starts with 5 or greater (and not "greater than 5"), we up the last digit.

      But the OPs problem wasn't with that. The OPs problem was the inconsistency of 0.255 being rounded up, and 1.255 being rounded down.

      That, however, you don't address. Others in the thread luckely did.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://423519]
Approved by kutsu
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (3)
As of 2020-05-27 04:10 GMT
Find Nodes?
    Voting Booth?
    If programming languages were movie genres, Perl would be:

    Results (152 votes). Check out past polls.