5

Can someone explain why there is a difference in behavior here?

perl -E 'say sprintf("%.2f",5.555);'
5.55    

perl -E 'say sprintf("%.2f",0.555);'
0.56  

I have read that sprintf() rounds up if the following digits is 5 or greater. So why doesn't it round up to 0.56 in the second case?

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Jim
  • 18,826
  • 34
  • 135
  • 254
  • 1
    Very good answers are here http://stackoverflow.com/q/24493228/632407 – clt60 Sep 12 '14 at 08:00
  • 1
    On a related note, `sprintf` rounds to even, so `sprintf '%.0f', 0.5` gives `0` and `sprintf '%.0f', 1.5` gives `2` even though `0.5` and `1.5` can be represented exactly as a floating point number. – ikegami Sep 12 '14 at 15:52

3 Answers3

9

The closest IEEE 754 64-bit binary floating point number to 0.555 is 0.55500000000000004884981308350688777863979339599609375. It is very slightly closer to 0.56 than to 0.55.

The closest IEEE 754 64-bit binary floating point number to 5.555 is 5.55499999999999971578290569595992565155029296875. It is very slightly closer to 5.55 than to 5.56.

In each case, the output is the nearest decimal with 2 decimal places to the actual value of the internal number.

As Pascal Cuoq says in a comment, 0.555 is in the binade [0.5 … 1), in which representable floating-point numbers are separated by 2-53. By contrast, 5.555 is in the binade [4 … 8), in which representable floating-point numbers are separated by 2-50. That is why the fractional parts are different for 0.555 and 5.555.

Pascal Cuoq
  • 79,187
  • 7
  • 161
  • 281
Patricia Shanahan
  • 25,849
  • 4
  • 38
  • 75
  • +1.How did you know about this representation? – Jim Sep 12 '14 at 07:52
  • 1
    @Jim I used Java: `System.out.println(new BigDecimal(0.555));`, but there are many ways of doing it, including web sites. – Patricia Shanahan Sep 12 '14 at 07:54
  • I don't understand what this ` 0.555 is in the binade [0.5 … 1),` means. Can you please explain it to me? – Jim Sep 12 '14 at 08:17
  • @Jim See [binade](http://en.wikipedia.org/wiki/Binade). It is just a range of numbers with the same exponent in IEEE floating point. – Patricia Shanahan Sep 12 '14 at 08:23
  • I have rolled back the latest edit because code tags were added to simple numbers and ranges that I meant in their mathematical sense, not as quotes from code. – Patricia Shanahan Sep 12 '14 at 11:25
5

Because printf rounds the value, just try:

perl -e 'printf("%.25f", 5.555)'

gives:

5.5549999999999997157829057

rounded to 5.55 with printf('%.2f', 5.55)

and

perl -e 'printf("%.25f", 0.555)'

gives

0.5550000000000000488498131

rounded to 0.56 with printf('%.2f', 0.55)

Toto
  • 89,455
  • 62
  • 89
  • 125
  • Why did you do .25f? How did you choose this 25? – Jim Sep 12 '14 at 07:53
  • @Jim: It's just an example to be sure to have a lot of decimal, you could do the same with `%.10` – Toto Sep 12 '14 at 07:56
  • +1.So basically the idea was to use a big formatter so that the number expands to see the actual representation? – Jim Sep 12 '14 at 08:16
1

If you want more consistent results, check Math::Round

perl -MMath::Round=:all -E 'say nearest(.01, 0.555)'
0.56

perl -MMath::Round=:all -E 'say nearest(.01, 5.555)'
5.56
mpapec
  • 50,217
  • 8
  • 67
  • 127
  • Is this library active?It was created in 2000.Sorry but due to my background I don't know how the perl libraries are maintained/supported – Jim Sep 12 '14 at 07:53
  • @Jim it was updated after that http://search.cpan.org/~grommel/Math-Round-0.06/ – mpapec Sep 12 '14 at 07:56
  • Even the update is in 2006.How can one know if it is actively used by many users? – Jim Sep 12 '14 at 07:57
  • It's being used by [these other modules](https://metacpan.org/requires/distribution/Math-Round?sort=[[2,1]]). – tobyink Sep 12 '14 at 09:26
  • @Jim Just because a module hasn't been updated in a while doesn't mean that it's not maintained. Often it means that the module Just Works and hasn't needed any updates. When you're not sure, also look at the [CPAN Testers results](http://www.cpantesters.org/distro/M/Math-Round.html?oncpan=1&distmat=1&version=0.06) for the module (in this case, 7315 passes and 1 failure) and the [active bug reports](https://rt.cpan.org/Public/Dist/Display.html?Name=Math-Round). Both of these are available from the sidebar if you look at the documentation on [metacpan](https://metacpan.org/pod/Math::Round). – ThisSuitIsBlackNot Sep 12 '14 at 14:38
  • @mpapec:I assume that the `.01` argument is to denote that we want decimal?What other alternatives could there have been? – Jim Sep 15 '14 at 20:42