I known the common way is to multiply 10^n and then divide 10^n. round a float with one digit number But due to the double precision accuracy problem, I found the solution above doesn't fully work for my case:
0.965 * 0.9 = 0.8685
std::round(0.8685 * 1000) / 1000 = 0.869
// expects it to be 0.869
std::round(0.965 * 0.9 * 1000) / 1000 = 0.868
If I want to get 0.869
from std::round(0.965 * 0.9 * 1000) / 1000
directly, I have to change the statement to
std::round((0.965 * 0.9 + std::numeric_limits<double>::epsilon()) * 1000) / 1000 = 0.869
Is there a simpler way to do the rounding without add an epsilon
for every calculation?
Edit: The problem is that, intuitively the value of std::round(0.965 * 0.9 * 1000) / 1000
shall be 0.869
(because 0.965 * 0.9 = 0.8685
), but it actually give 0.868
. I want to find common way get the accurate math value with 3 decimal precision.
This is actually a surprisingly non-trivial problem, unless your problem is merely concerned with formatting output, in which case you can use an appropriate printf
-style formatter, or ostream
manipulator.
Fundamentally, denary rounding using a binary type doesn't make much sense. Your specific problem is due to the closest IEEE754 double
to 0.965
being
0.96499999999999996891375531049561686813831329345703125
Your first port of call is to study Is floating point math broken?. Hopefully that will convince you that adding an arbitrary "epsilon" merely shifts the problem to other inputs, and there is no numerical justification for your using std::numeric_limits<double>::epsilon()
either.
std::round
works perfectly, due in part that the cutoff point x.5
for integer x
is a dyadic rational so can be represented exactly in binary floating point. But alas, you can't use that to round to an arbitrary decimal point.
If you're willing to live with the occasional bad result then the std::round(x * y) / y
idiom that you're currently using is probably your best bet.
If you can't live with any spurious errors, then you probably need to use a decimal type and perform the rounding functions on that. See C++ decimal data types
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With