Stéphane
Stéphane

Reputation: 20370

Should I add a tiny amount when trying to use std::round()?

Here is a situation where a round_to_2_digits() function is rounding down when we expected it to round up. This turned out to be the case where a number cannot be represented exactly in a double. I don't remember the exact value, but say this:

double value = 1.155;
double value_rounded = round_to_2_digits( value );

The value was the output of a function, and instead of being exactly 1.155 like the code above, it actually was returning something like 1.15499999999999999. So calling std::round() on it would result in 1.15 instead of 1.16 like we thought.

Questions:

I'm thinking it may be wise to add a tiny value in round_to_2_digits() prior to calling std::round().

The rounding function is quite simple:

double round_to_2_decimals( double value )
{
    value *= 100.0;
    value = std::round(value);
    value /= 100.0;
    return value;
}

Upvotes: 1

Views: 184

Answers (2)

Mark Bessey
Mark Bessey

Reputation: 19782

Step one is admitting that double may not be the right data type for your application. :-) Consider using a fixed-point type, or multiplying all of your values by 100 (or 1000, or whatever), and working with integer values.

You can't actually guarantee that adding any particular small epsilon won't give you the wrong results in some other situation. What if your value actually was 1.54999999..., and you rounded it up? Then you'd have the wrong value the other way.

The problem with your suggested solution is that at the end of it, you're still going to have a binary fraction that's not necessarily equal to the decimal value you're trying to represent. The only way to fix this is to use a representation that can exactly represent the values you want to use.

Upvotes: 2

user5535385
user5535385

Reputation: 9

This question doesn't make a lot of sense. POSIX mandates std::round rounds half away from zero. So the result should in fact be 116 not 115. In order to actually replicate your behavior, I had to use a function that pays attention to rounding mode:

std::fesetround(FE_DOWNWARD);
std::cout << std::setprecision(20) << std::rint(1.155 * 100.0);

This was tested on GCC 5.2.0 and Clang 3.7.0.

Upvotes: 0

Related Questions