15/100 is a periodic number in binary, so it can't be stored accurately as a float.
` ____
1.15 base10 = 1.001001 base2
`
This error causes 3010*1.15 to be equal to 3461.4999999999995, which Math::Round is correctly rounding to 3461.
You need to incorporate a tolerance. Since 1/2 can be stored precisely in a floating point number (0.5_{10} = 0.1_{2}), you can use the following:
`use feature qw( say );
use Math::Round qw( round );
my $x = 3010*1.15;
say round($x);
say round(round($x * 10**5) / 10**5); # 5 decimal places of precision
`
`3461
3462
`
This is basically what tye did by stringifying the number, except he let Perl "choose" the factor.
| [reply] [d/l] [select] |

Have you read the Standard Floating-Point Disclaimer, as is part of Math::Round?
Your situation may be one where it applies.
POSIX::ceil and POSIX::floor don't do rounding, they truncate towards an integer number. Maybe you can explain what results you expect and what results you get. Also, please supply code and data we can use to easily replicate your situation.
| [reply] |

Updated original post with edit 2.
| [reply] |

When the number is actually 3461.49999999999999382 it should be rounded to 3461 but might be displayed as simply "3461.5".
**Edit 1** in response to at least the second "edit" labeled "Edit 2" above (for sanity's sake, please stop changing the root of this conversation):
`perl -e 'print sprintf("%.20f",(3010*1.15))."\n"' # Outputs 3461.49999
+999999950000000
`
QED. (Now, maybe you'll go read and try to understand the stuff about floating point that was linked to quite a while ago?)
| [reply] [d/l] |

| [reply] |

You got 3461.49999999999950000000? Because I didn't.
What's your OS name and version? What's your perl version? Perhaps we have a difference of some math library or something.
(Prior node quoted in entirety due to rash of prior "edit"s.)
So I edited my prior node to correct my mis-paste. Clearly "%.4f" would not yield that many trailing digits. To get 20 trailing digits, I clearly had used "%.20f" (which is what my node now shows). (I also replied as edits are not so easy to notice, naturally.)
Please try again.
| [reply] |

In response to `3010*1.15`: 1.15 is not a number that can be represented exactly in base-2, or as a sum of 1/(2**n) factors. Because of that, you will necessarily (given no access to a fractional number library of some sort) need to approximate the value when stored as a floating point. This is why your rounding looks weird. The closest you are able to get is:
`1 + (1/8) + (1/64) + (1/128) + (1/1024) + (1/2048) ...`
This basically goes for a ReallyLongTime™. Printf rounds to a specific number of digits unless told otherwise, as tye and others have illustrated. What Every Computer Scientist Should Know About Floating Point is a better explanation of this than I have time to give here, and should be required reading for any programming course dealing with numerical representation in hardware.
| [reply] [d/l] [select] |

There are two different issues. One is the general issue about floating point arithmetic, with the problems between binary and decimal representations of floats, well covered for example in the What Every Computer Scientist Should Know About Floating-Point Arithmetic document that has already been mentioned. But this is only part of the story.
I have already stated that above, but no one seems to have noticed. The other problem is that the international IEEE standard for rounding numbers has enforced rules which are not what most people think. According to this international standard, the rule for **true rounding** is this: when you want to round a number with one decimal place to an integer, numbers whose decimal place is 5 will be rounded up when the previous digit is odd and down when the previous digit even. So that, **when rounding to an integer, 1.5 and 2.5 should both be rounded to 2** .
Consider for example this illustration of true rounding according to international standards:
`$ perl -e 'printf " %.1f => %.0f\n", $_, $_ for qw / .5 1.5 2.5 3.5 4
+.5 5.5 6.5 7.5 8.5 9.5/;'
0.5 => 0
1.5 => 2
2.5 => 2
3.5 => 4
4.5 => 4
5.5 => 6
6.5 => 6
7.5 => 8
8.5 => 8
9.5 => 10
`
This is what is considered correct. This is the international standard, and this is what the standard C library implements for the round function, and this is what Perl is also doing, presumably because it is based on the C library. (I have already explained in my post above the rationale for this apparently pesky rule.)
Now to your problem with 3461.5 and to what you have added in your successive edits of your post. If I want to round that number, I get this:
`$ perl -e 'printf " %.0f \n", 3461.5;'
3462
$ perl -e 'printf " %.0f \n", 3462.5;'
3462
`
The last integer digit in 3461.5 is odd, so its gets rounded up. and 3462.5 is rounded down to the same number. Fair enough, that's the rule stated above.
Now when you using your multiplication for creating 3461.5:
`$ perl -e 'printf " %.0f \n", 3010*1.15,'
3461
`
Why? Well, if you want to know, try this:
`$ perl -e 'printf "%.15f \n", 3010*1.15,'
3461.499999999999545
`
As you can see, the internal representation of 3010*1.15 is actually slightly smaller than 3461.5, so it should logically be rounded down. This is due to the fact that 1.15 expressed in binary representation is periodical, i.e. a number with an infinite number of digits (just like 1/3 in decimal representation: 0.333333333...). If our computers were using internal decimal representation with, say, 13 decimal digits, 1/3 would have to be stored, say, as 0,3333333333333, meaning that the ...333... of the 14th, 15th, 16th, etc. digits are rounded down. Similarly, in binary format, 1.15 is truncated of some of its digits after a certain number of "decimal" places, to that the multiplication results in a number smaller than 3461.5. BTW, to get a, idea of the decimal value of the internal binary representation of 1.15, just try the same thing:
`$ perl -e 'printf "%.19f \n", 1.15;'
1.1499999999999999112
`
A near miss, but not quite exactly 1.15.
And, by the way, just changing very slightly the numbers in your product yields the result you expect:
`$ perl -e 'printf " %.0f \n", 301*11.5;'
3462
`
because 11.5 is not a periodical number in its binary representation. The difference between 301*11.5 and 3010*1.15 is:
`$ perl -E 'say 301*11.5 - 3010*1.15;'
4.54747350886464e-13
`
*Update:* Corrected a typo in the second paragraph: "when the previous digit is odd" (and not "is off" as I had written). Thanks to N-Wing for picking it up.
| [reply] [d/l] [select] |

Asides from the general comment on floating-point arithmetic calculation, you should know that the international IEEE standard for rounding numbers is more complicated that what you probably expect. If you want to round a number with one decimal place to an integer, numbers whose decimal place is 5 will be rounded up or down, depending on whether the previous digit is odd or even. This is the international standard, and this is what the standard C library implements for the round function, and this is what Perl is also doing, presumably because it is based on the C library. The rational for that is that if you always round up numbers with one decimal place equal to 5, you get a bias upward in sums of large number of numbers. So that a number with one decimal place equal to 5 is sometimes rounded up and sometimes rounded down.
| [reply] |

Thank you, but if you look at my added test programs in Edit 2, you will see the number actually is "3461.5000", and it should be rounded to "3462".
| [reply] |

| [reply] |

| [reply] |

tye is talking about that:
`$ perl -e 'printf "%.10f\n%.30f\n", 3010*1.15, 3010*1.15'
3461.5000000000
3461.499999999999545252649113535881
`
So it seems a quick and dirty hack would be to `sprintf` the number and then round the string? :) | [reply] [d/l] [select] |

`$l=Math::Round::round("$x");
# Math::Round::round($x) # vs. this
`
If what you care about is how the rounding compares to the string output for the number, then what you should be rounding is the string output, of course.
| [reply] [d/l] |

Hmm. Well this seemed to work in this case. I'll test it out.
perl -e 'print int(sprintf("%.10f",(3010*1.15))+0.5)."\n"'
| [reply] |

Any rounding discipline is a compromise. The IEEE rounding is at least "good enough" for almost all applications. If you are certain that it is not for yours, you probably know enough to write a special one for this application only. What about negative numbers? Have you considered the floating point issue correctly?
| [reply] |

Comment onMath::round not rounding correctly