std::nearbyint vs std::round in C++11

Viewed 7498

C++11 introduced the std::nearbyint and std::round functions. Both return the "nearest" integer value.

When and where should I prefer one over the other?

I have tested them with the value of 0.5:

Case 1 : Demo for nearbyint

#include <iostream>
#include <cmath>

int main()
{
    std::cout<<"nearbyint(0.5) = "<<std::nearbyint(0.5);
}

output: 0

Case 2 : Demo for round

#include <iostream>
#include <cmath>

int main()
{
    std::cout<<"round(0.5) = "<<std::round(0.5);
}

output: 1

Why are the outputs different?

2 Answers

The std::round function ignores the current rounding mode while the std::nearbyint takes it into account. You can change the rounding mode:

#include <cfenv>
int main() {
    std::fesetround(FE_UPWARD);
    // perform calculations
    std::fesetround(FE_DOWNWARD);
    // perform calculations
    // other rounding methods...
}

and observe different results. To obtain the current rounding mode value use the std::fegetround() function. Chances are the default (implementation defined) value is 0 which translates to FE_TONEAREST.

As pointed out in Ron's answer, one difference between rint() and nearbyint() on one hand, and round() on the other hand, is that the latter uses a fixed rounding mode, regardless of the dynamic rounding mode currently in effect. The details of this cannot be found in the 2011 ISO C++ standard, which in section 26.8 C library [c.math] simply points to the C standard. The 1999 ISO C standard specifies the operation of round() as follows:

7.12.9.6 [...] The round functions round their argument to the nearest integer value in floating-point format, rounding halfway cases away from zero, regardless of the current rounding direction.

The specific rounding mode used by round() is listed in section 4.3.1 of the IEEE 754 (2008) floating-point standard as roundTiesToAway, meaning tie cases are rounded away from zero. But the usual binding of FE_TONEAREST is to the IEEE-754 (2008) rounding mode roundTiesToEven, meaning such tie cases round to an even integer. In fact, that is the only implementation of FE_TONEAREST I have ever encountered on any of numerous system platforms I have used that support fesetround().

The difference in the handling of these two variants of rounding "to nearest" is apparent in the asker's example: 0.5 rounds to the next larger (in magnitude) integer (1) when using round(), but it rounds to an even integer (0) when nearbyint() or rint() are used.

Related