I need a simple floating point rounding function, thus:
double round(double);
round(0.1) = 0
round(-0.1) = 0
round(-0.9) = -1
I can find ceil()
and floor()
in the math.h - but not round()
.
Is it present in the standard C++ library under another name, or is it missing??
This question is related to
c++
floating-point
rounding
There's no round() in the C++98 standard library. You can write one yourself though. The following is an implementation of round-half-up:
double round(double d)
{
return floor(d + 0.5);
}
The probable reason there is no round function in the C++98 standard library is that it can in fact be implemented in different ways. The above is one common way but there are others such as round-to-even, which is less biased and generally better if you're going to do a lot of rounding; it's a bit more complex to implement though.
Beware of floor(x+0.5)
. Here is what can happen for odd numbers in range [2^52,2^53]:
-bash-3.2$ cat >test-round.c <<END
#include <math.h>
#include <stdio.h>
int main() {
double x=5000000000000001.0;
double y=round(x);
double z=floor(x+0.5);
printf(" x =%f\n",x);
printf("round(x) =%f\n",y);
printf("floor(x+0.5)=%f\n",z);
return 0;
}
END
-bash-3.2$ gcc test-round.c
-bash-3.2$ ./a.out
x =5000000000000001.000000
round(x) =5000000000000001.000000
floor(x+0.5)=5000000000000002.000000
This is http://bugs.squeak.org/view.php?id=7134. Use a solution like the one of @konik.
My own robust version would be something like:
double round(double x)
{
double truncated,roundedFraction;
double fraction = modf(x, &truncated);
modf(2.0*fraction, &roundedFraction);
return truncated + roundedFraction;
}
Another reason to avoid floor(x+0.5) is given here.
I did this:
#include <cmath.h>
using namespace std;
double roundh(double number, int place){
/* place = decimal point. Putting in 0 will make it round to whole
number. putting in 1 will round to the
tenths digit.
*/
number *= 10^place;
int istack = (int)floor(number);
int out = number-istack;
if (out < 0.5){
floor(number);
number /= 10^place;
return number;
}
if (out > 0.4) {
ceil(number);
number /= 10^place;
return number;
}
}
It may be worth noting that if you wanted an integer result from the rounding you don't need to pass it through either ceil or floor. I.e.,
int round_int( double r ) {
return (r > 0.0) ? (r + 0.5) : (r - 0.5);
}
Beware of floor(x+0.5)
. Here is what can happen for odd numbers in range [2^52,2^53]:
-bash-3.2$ cat >test-round.c <<END
#include <math.h>
#include <stdio.h>
int main() {
double x=5000000000000001.0;
double y=round(x);
double z=floor(x+0.5);
printf(" x =%f\n",x);
printf("round(x) =%f\n",y);
printf("floor(x+0.5)=%f\n",z);
return 0;
}
END
-bash-3.2$ gcc test-round.c
-bash-3.2$ ./a.out
x =5000000000000001.000000
round(x) =5000000000000001.000000
floor(x+0.5)=5000000000000002.000000
This is http://bugs.squeak.org/view.php?id=7134. Use a solution like the one of @konik.
My own robust version would be something like:
double round(double x)
{
double truncated,roundedFraction;
double fraction = modf(x, &truncated);
modf(2.0*fraction, &roundedFraction);
return truncated + roundedFraction;
}
Another reason to avoid floor(x+0.5) is given here.
There are 2 problems we are looking at:
Rounding conversions mean rounding ± float/double to nearest floor/ceil float/double. May be your problem ends here. But if you are expected to return Int/Long, you need to perform type conversion, and thus "Overflow" problem might hit your solution. SO, do a check for error in your function
long round(double x) {
assert(x >= LONG_MIN-0.5);
assert(x <= LONG_MAX+0.5);
if (x >= 0)
return (long) (x+0.5);
return (long) (x-0.5);
}
#define round(x) ((x) < LONG_MIN-0.5 || (x) > LONG_MAX+0.5 ?\
error() : ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
Best way to rounding off a floating value by "n" decimal places, is as following with in O(1) time:-
We have to round off the value by 3 places i.e. n=3.So,
float a=47.8732355;
printf("%.3f",a);
It's usually implemented as floor(value + 0.5)
.
Edit: and it's probably not called round since there are at least three rounding algorithms I know of: round to zero, round to closest integer, and banker's rounding. You are asking for round to closest integer.
There is no need to implement anything, so I'm not sure why so many answers involve defines, functions, or methods.
In C99
We have the following and and header <tgmath.h> for type-generic macros.
#include <math.h>
double round (double x);
float roundf (float x);
long double roundl (long double x);
If you cannot compile this, you have probably left out the math library. A command similar to this works on every C compiler I have (several).
gcc -lm -std=c99 ...
In C++11
We have the following and additional overloads in #include <cmath> that rely on IEEE double precision floating point.
#include <math.h>
double round (double x);
float round (float x);
long double round (long double x);
double round (T x);
There are equivalents in the std namespace too.
If you cannot compile this, you may be using C compilation instead of C++. The following basic command produces neither errors nor warnings with g++ 6.3.1, x86_64-w64-mingw32-g++ 6.3.0, clang-x86_64++ 3.8.0, and Visual C++ 2015 Community.
g++ -std=c++11 -Wall
With Ordinal Division
When dividing two ordinal numbers, where T is short, int, long, or another ordinal, the rounding expression is this.
T roundedQuotient = (2 * integerNumerator + 1)
/ (2 * integerDenominator);
Accuracy
There is no doubt that odd looking inaccuracies appear in floating point operations, but this is only when the numbers appear, and has little to do with rounding.
The source is not just the number of significant digits in the mantissa of the IEEE representation of a floating point number, it is related to our decimal thinking as humans.
Ten is the product of five and two, and 5 and 2 are relatively prime. Therefore the IEEE floating point standards cannot possibly be represented perfectly as decimal numbers for all binary digital representations.
This is not an issue with the rounding algorithms. It is mathematical reality that should be considered during the selection of types and the design of computations, data entry, and display of numbers. If an application displays the digits that show these decimal-binary conversion issues, then the application is visually expressing accuracy that does not exist in digital reality and should be changed.
There's no round() in the C++98 standard library. You can write one yourself though. The following is an implementation of round-half-up:
double round(double d)
{
return floor(d + 0.5);
}
The probable reason there is no round function in the C++98 standard library is that it can in fact be implemented in different ways. The above is one common way but there are others such as round-to-even, which is less biased and generally better if you're going to do a lot of rounding; it's a bit more complex to implement though.
I did this:
#include <cmath.h>
using namespace std;
double roundh(double number, int place){
/* place = decimal point. Putting in 0 will make it round to whole
number. putting in 1 will round to the
tenths digit.
*/
number *= 10^place;
int istack = (int)floor(number);
int out = number-istack;
if (out < 0.5){
floor(number);
number /= 10^place;
return number;
}
if (out > 0.4) {
ceil(number);
number /= 10^place;
return number;
}
}
Based on Kalaxy's response, the following is a templated solution that rounds any floating point number to the nearest integer type based on natural rounding. It also throws an error in debug mode if the value is out of range of the integer type, thereby serving roughly as a viable library function.
// round a floating point number to the nearest integer
template <typename Arg>
int Round(Arg arg)
{
#ifndef NDEBUG
// check that the argument can be rounded given the return type:
if (
(Arg)std::numeric_limits<int>::max() < arg + (Arg) 0.5) ||
(Arg)std::numeric_limits<int>::lowest() > arg - (Arg) 0.5)
)
{
throw std::overflow_error("out of bounds");
}
#endif
return (arg > (Arg) 0.0) ? (int)(r + (Arg) 0.5) : (int)(r - (Arg) 0.5);
}
There's no round() in the C++98 standard library. You can write one yourself though. The following is an implementation of round-half-up:
double round(double d)
{
return floor(d + 0.5);
}
The probable reason there is no round function in the C++98 standard library is that it can in fact be implemented in different ways. The above is one common way but there are others such as round-to-even, which is less biased and generally better if you're going to do a lot of rounding; it's a bit more complex to implement though.
As pointed out in comments and other answers, the ISO C++ standard library did not add round()
until ISO C++11, when this function was pulled in by reference to the ISO C99 standard math library.
For positive operands in [½, ub] round(x) == floor (x + 0.5)
, where ub is 223 for float
when mapped to IEEE-754 (2008) binary32
, and 252 for double
when it is mapped to IEEE-754 (2008) binary64
. The numbers 23 and 52 correspond to the number of stored mantissa bits in these two floating-point formats. For positive operands in [+0, ½) round(x) == 0
, and for positive operands in (ub, +8] round(x) == x
. As the function is symmetric about the x-axis, negative arguments x
can be handled according to round(-x) == -round(x)
.
This leads to the compact code below. It compiles into a reasonable number of machine instructions across various platforms. I observed the most compact code on GPUs, where my_roundf()
requires about a dozen instructions. Depending on processor architecture and toolchain, this floating-point based approach could be either faster or slower than the integer-based implementation from newlib referenced in a different answer.
I tested my_roundf()
exhaustively against the newlib roundf()
implementation using Intel compiler version 13, with both /fp:strict
and /fp:fast
. I also checked that the newlib version matches the roundf()
in the mathimf
library of the Intel compiler. Exhaustive testing is not possible for double-precision round()
, however the code is structurally identical to the single-precision implementation.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
float my_roundf (float x)
{
const float half = 0.5f;
const float one = 2 * half;
const float lbound = half;
const float ubound = 1L << 23;
float a, f, r, s, t;
s = (x < 0) ? (-one) : one;
a = x * s;
t = (a < lbound) ? x : s;
f = (a < lbound) ? 0 : floorf (a + half);
r = (a > ubound) ? x : (t * f);
return r;
}
double my_round (double x)
{
const double half = 0.5;
const double one = 2 * half;
const double lbound = half;
const double ubound = 1ULL << 52;
double a, f, r, s, t;
s = (x < 0) ? (-one) : one;
a = x * s;
t = (a < lbound) ? x : s;
f = (a < lbound) ? 0 : floor (a + half);
r = (a > ubound) ? x : (t * f);
return r;
}
uint32_t float_as_uint (float a)
{
uint32_t r;
memcpy (&r, &a, sizeof(r));
return r;
}
float uint_as_float (uint32_t a)
{
float r;
memcpy (&r, &a, sizeof(r));
return r;
}
float newlib_roundf (float x)
{
uint32_t w;
int exponent_less_127;
w = float_as_uint(x);
/* Extract exponent field. */
exponent_less_127 = (int)((w & 0x7f800000) >> 23) - 127;
if (exponent_less_127 < 23) {
if (exponent_less_127 < 0) {
/* Extract sign bit. */
w &= 0x80000000;
if (exponent_less_127 == -1) {
/* Result is +1.0 or -1.0. */
w |= ((uint32_t)127 << 23);
}
} else {
uint32_t exponent_mask = 0x007fffff >> exponent_less_127;
if ((w & exponent_mask) == 0) {
/* x has an integral value. */
return x;
}
w += 0x00400000 >> exponent_less_127;
w &= ~exponent_mask;
}
} else {
if (exponent_less_127 == 128) {
/* x is NaN or infinite so raise FE_INVALID by adding */
return x + x;
} else {
return x;
}
}
x = uint_as_float (w);
return x;
}
int main (void)
{
uint32_t argi, resi, refi;
float arg, res, ref;
argi = 0;
do {
arg = uint_as_float (argi);
ref = newlib_roundf (arg);
res = my_roundf (arg);
resi = float_as_uint (res);
refi = float_as_uint (ref);
if (resi != refi) { // check for identical bit pattern
printf ("!!!! arg=%08x res=%08x ref=%08x\n", argi, resi, refi);
return EXIT_FAILURE;
}
argi++;
} while (argi);
return EXIT_SUCCESS;
}
Since C++ 11 simply:
#include <cmath>
std::round(1.1)
or to get int
static_cast<int>(std::round(1.1))
There are 2 problems we are looking at:
Rounding conversions mean rounding ± float/double to nearest floor/ceil float/double. May be your problem ends here. But if you are expected to return Int/Long, you need to perform type conversion, and thus "Overflow" problem might hit your solution. SO, do a check for error in your function
long round(double x) {
assert(x >= LONG_MIN-0.5);
assert(x <= LONG_MAX+0.5);
if (x >= 0)
return (long) (x+0.5);
return (long) (x-0.5);
}
#define round(x) ((x) < LONG_MIN-0.5 || (x) > LONG_MAX+0.5 ?\
error() : ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
If you ultimately want to convert the double
output of your round()
function to an int
, then the accepted solutions of this question will look something like:
int roundint(double r) {
return (int)((r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5));
}
This clocks in at around 8.88 ns on my machine when passed in uniformly random values.
The below is functionally equivalent, as far as I can tell, but clocks in at 2.48 ns on my machine, for a significant performance advantage:
int roundint (double r) {
int tmp = static_cast<int> (r);
tmp += (r-tmp>=.5) - (r-tmp<=-.5);
return tmp;
}
Among the reasons for the better performance is the skipped branching.
Boost offers a simple set of rounding functions.
#include <boost/math/special_functions/round.hpp>
double a = boost::math::round(1.5); // Yields 2.0
int b = boost::math::iround(1.5); // Yields 2 as an integer
For more information, see the Boost documentation.
Edit: Since C++11, there are std::round
, std::lround
, and std::llround
.
You could round to n digits precision with:
double round( double x )
{
const double sd = 1000; //for accuracy to 3 decimal places
return int(x*sd + (x<0? -0.5 : 0.5))/sd;
}
It's usually implemented as floor(value + 0.5)
.
Edit: and it's probably not called round since there are at least three rounding algorithms I know of: round to zero, round to closest integer, and banker's rounding. You are asking for round to closest integer.
If you need to be able to compile code in environments that support the C++11 standard, but also need to be able to compile that same code in environments that don't support it, you could use a function macro to choose between std::round() and a custom function for each system. Just pass -DCPP11
or /DCPP11
to the C++11-compliant compiler (or use its built-in version macros), and make a header like this:
// File: rounding.h
#include <cmath>
#ifdef CPP11
#define ROUND(x) std::round(x)
#else /* CPP11 */
inline double myRound(double x) {
return (x >= 0.0 ? std::floor(x + 0.5) : std::ceil(x - 0.5));
}
#define ROUND(x) myRound(x)
#endif /* CPP11 */
For a quick example, see http://ideone.com/zal709 .
This approximates std::round() in environments that aren't C++11-compliant, including preservation of the sign bit for -0.0. It may cause a slight performance hit, however, and will likely have issues with rounding certain known "problem" floating-point values such as 0.49999999999999994 or similar values.
Alternatively, if you have access to a C++11-compliant compiler, you could just grab std::round() from its <cmath>
header, and use it to make your own header that defines the function if it's not already defined. Note that this may not be an optimal solution, however, especially if you need to compile for multiple platforms.
The C++03 standard relies on the C90 standard for what the standard calls the Standard C Library which is covered in the draft C++03 standard (closest publicly available draft standard to C++03 is N1804) section 1.2
Normative references:
The library described in clause 7 of ISO/IEC 9899:1990 and clause 7 of ISO/IEC 9899/Amd.1:1995 is hereinafter called the Standard C Library.1)
If we go to the C documentation for round, lround, llround on cppreference we can see that round and related functions are part of C99 and thus won't be available in C++03 or prior.
In C++11 this changes since C++11 relies on the C99 draft standard for C standard library and therefore provides std::round and for integral return types std::lround, std::llround :
#include <iostream>
#include <cmath>
int main()
{
std::cout << std::round( 0.4 ) << " " << std::lround( 0.4 ) << " " << std::llround( 0.4 ) << std::endl ;
std::cout << std::round( 0.5 ) << " " << std::lround( 0.5 ) << " " << std::llround( 0.5 ) << std::endl ;
std::cout << std::round( 0.6 ) << " " << std::lround( 0.6 ) << " " << std::llround( 0.6 ) << std::endl ;
}
Another option also from C99 would be std::trunc which:
Computes nearest integer not greater in magnitude than arg.
#include <iostream>
#include <cmath>
int main()
{
std::cout << std::trunc( 0.4 ) << std::endl ;
std::cout << std::trunc( 0.9 ) << std::endl ;
std::cout << std::trunc( 1.1 ) << std::endl ;
}
If you need to support non C++11 applications your best bet would be to use boost round, iround, lround, llround or boost trunc.
Rolling your own version of round is hard
Rolling your own is probably not worth the effort as Harder than it looks: rounding float to nearest integer, part 1, Rounding float to nearest integer, part 2 and Rounding float to nearest integer, part 3 explain:
For example a common roll your implementation using std::floor
and adding 0.5
does not work for all inputs:
double myround(double d)
{
return std::floor(d + 0.5);
}
One input this will fail for is 0.49999999999999994
, (see it live).
Another common implementation involves casting a floating point type to an integral type, which can invoke undefined behavior in the case where the integral part can not be represented in the destination type. We can see this from the draft C++ standard section 4.9
Floating-integral conversions which says (emphasis mine):
A prvalue of a floating point type can be converted to a prvalue of an integer type. The conversion truncates; that is, the fractional part is discarded. The behavior is undefined if the truncated value cannot be represented in the destination type.[...]
For example:
float myround(float f)
{
return static_cast<float>( static_cast<unsigned int>( f ) ) ;
}
Given std::numeric_limits<unsigned int>::max()
is 4294967295
then the following call:
myround( 4294967296.5f )
will cause overflow, (see it live).
We can see how difficult this really is by looking at this answer to Concise way to implement round() in C? which referencing newlibs version of single precision float round. It is a very long function for something which seems simple. It seems unlikely that anyone without intimate knowledge of floating point implementations could correctly implement this function:
float roundf(x)
{
int signbit;
__uint32_t w;
/* Most significant word, least significant word. */
int exponent_less_127;
GET_FLOAT_WORD(w, x);
/* Extract sign bit. */
signbit = w & 0x80000000;
/* Extract exponent field. */
exponent_less_127 = (int)((w & 0x7f800000) >> 23) - 127;
if (exponent_less_127 < 23)
{
if (exponent_less_127 < 0)
{
w &= 0x80000000;
if (exponent_less_127 == -1)
/* Result is +1.0 or -1.0. */
w |= ((__uint32_t)127 << 23);
}
else
{
unsigned int exponent_mask = 0x007fffff >> exponent_less_127;
if ((w & exponent_mask) == 0)
/* x has an integral value. */
return x;
w += 0x00400000 >> exponent_less_127;
w &= ~exponent_mask;
}
}
else
{
if (exponent_less_127 == 128)
/* x is NaN or infinite. */
return x + x;
else
return x;
}
SET_FLOAT_WORD(x, w);
return x;
}
On the other hand if none of the other solutions are usable newlib could potentially be an option since it is a well tested implementation.
Best way to rounding off a floating value by "n" decimal places, is as following with in O(1) time:-
We have to round off the value by 3 places i.e. n=3.So,
float a=47.8732355;
printf("%.3f",a);
It may be worth noting that if you wanted an integer result from the rounding you don't need to pass it through either ceil or floor. I.e.,
int round_int( double r ) {
return (r > 0.0) ? (r + 0.5) : (r - 0.5);
}
These days it shouldn't be a problem to use a C++11 compiler which includes a C99/C++11 math library. But then the question becomes: which rounding function do you pick?
C99/C++11 round()
is often not actually the rounding function you want. It uses a funky rounding mode that rounds away from 0 as a tie-break on half-way cases (+-xxx.5000
). If you do specifically want that rounding mode, or you're targeting a C++ implementation where round()
is faster than rint()
, then use it (or emulate its behaviour with one of the other answers on this question which took it at face value and carefully reproduced that specific rounding behaviour.)
round()
's rounding is different from the IEEE754 default round to nearest mode with even as a tie-break. Nearest-even avoids statistical bias in the average magnitude of numbers, but does bias towards even numbers.
There are two math library rounding functions that use the current default rounding mode: std::nearbyint()
and std::rint()
, both added in C99/C++11, so they're available any time std::round()
is. The only difference is that nearbyint
never raises FE_INEXACT.
Prefer rint()
for performance reasons: gcc and clang both inline it more easily, but gcc never inlines nearbyint()
(even with -ffast-math
)
I put some test functions on Matt Godbolt's Compiler Explorer, where you can see source + asm output (for multiple compilers). For more about reading compiler output, see this Q&A, and Matt's CppCon2017 talk: “What Has My Compiler Done for Me Lately? Unbolting the Compiler's Lid”,
In FP code, it's usually a big win to inline small functions. Especially on non-Windows, where the standard calling convention has no call-preserved registers, so the compiler can't keep any FP values in XMM registers across a call
. So even if you don't really know asm, you can still easily see whether it's just a tail-call to the library function or whether it inlined to one or two math instructions. Anything that inlines to one or two instructions is better than a function call (for this particular task on x86 or ARM).
On x86, anything that inlines to SSE4.1 roundsd
can auto-vectorize with SSE4.1 roundpd
(or AVX vroundpd
). (FP->integer conversions are also available in packed SIMD form, except for FP->64-bit integer which requires AVX512.)
std::nearbyint()
:
-msse4.1
.-msse4.1 -ffast-math
, and only on gcc 5.4 and earlier. Later gcc never inlines it (maybe they didn't realize that one of the immediate bits can suppress the inexact exception? That's what clang uses, but older gcc uses the same immediate as for rint
when it does inline it)std::rint
:
-msse4.1
-msse4.1
. (Without SSE4.1, inlines to several instructions)-ffast-math -msse4.1
.std::round
:
-ffast-math -msse4.1
, requiring two vector constants.std::floor
/ std::ceil
/ std::trunc
-msse4.1
-msse4.1
-ffast-math -msse4.1
int
/ long
/ long long
:You have two options here: use lrint
(like rint
but returns long
, or long long
for llrint
), or use an FP->FP rounding function and then convert to an integer type the normal way (with truncation). Some compilers optimize one way better than the other.
long l = lrint(x);
int i = (int)rint(x);
Note that int i = lrint(x)
converts float
or double
-> long
first, and then truncates the integer to int
. This makes a difference for out-of-range integers: Undefined Behaviour in C++, but well-defined for the x86 FP -> int instructions (which the compiler will emit unless it sees the UB at compile time while doing constant propagation, then it's allowed to make code that breaks if it's ever executed).
On x86, an FP->integer conversion that overflows the integer produces INT_MIN
or LLONG_MIN
(a bit-pattern of 0x8000000
or the 64-bit equivalent, with just the sign-bit set). Intel calls this the "integer indefinite" value. (See the cvttsd2si
manual entry, the SSE2 instruction that converts (with truncation) scalar double to signed integer. It's available with 32-bit or 64-bit integer destination (in 64-bit mode only). There's also a cvtsd2si
(convert with current rounding mode), which is what we'd like the compiler to emit, but unfortunately gcc and clang won't do that without -ffast-math
.
Also beware that FP to/from unsigned
int / long is less efficient on x86 (without AVX512). Conversion to 32-bit unsigned on a 64-bit machine is pretty cheap; just convert to 64-bit signed and truncate. But otherwise it's significantly slower.
x86 clang with/without -ffast-math -msse4.1
: (int/long)rint
inlines to roundsd
/ cvttsd2si
. (missed optimization to cvtsd2si
). lrint
doesn't inline at all.
x86 gcc6.x and earlier without -ffast-math
: neither way inlines
-ffast-math
: (int/long)rint
rounds and converts separately (with 2 total instructions of SSE4.1 is enabled, otherwise with a bunch of code inlined for rint
without roundsd
). lrint
doesn't inline.x86 gcc with -ffast-math
: all ways inline to cvtsd2si
(optimal), no need for SSE4.1.
AArch64 gcc6.3 without -ffast-math
: (int/long)rint
inlines to 2 instructions. lrint
doesn't inline
-ffast-math
: (int/long)rint
compiles to a call to lrint
. lrint
doesn't inline. This may be a missed optimization unless the two instructions we get without -ffast-math
are very slow.There's no round() in the C++98 standard library. You can write one yourself though. The following is an implementation of round-half-up:
double round(double d)
{
return floor(d + 0.5);
}
The probable reason there is no round function in the C++98 standard library is that it can in fact be implemented in different ways. The above is one common way but there are others such as round-to-even, which is less biased and generally better if you're going to do a lot of rounding; it's a bit more complex to implement though.
There is no need to implement anything, so I'm not sure why so many answers involve defines, functions, or methods.
In C99
We have the following and and header <tgmath.h> for type-generic macros.
#include <math.h>
double round (double x);
float roundf (float x);
long double roundl (long double x);
If you cannot compile this, you have probably left out the math library. A command similar to this works on every C compiler I have (several).
gcc -lm -std=c99 ...
In C++11
We have the following and additional overloads in #include <cmath> that rely on IEEE double precision floating point.
#include <math.h>
double round (double x);
float round (float x);
long double round (long double x);
double round (T x);
There are equivalents in the std namespace too.
If you cannot compile this, you may be using C compilation instead of C++. The following basic command produces neither errors nor warnings with g++ 6.3.1, x86_64-w64-mingw32-g++ 6.3.0, clang-x86_64++ 3.8.0, and Visual C++ 2015 Community.
g++ -std=c++11 -Wall
With Ordinal Division
When dividing two ordinal numbers, where T is short, int, long, or another ordinal, the rounding expression is this.
T roundedQuotient = (2 * integerNumerator + 1)
/ (2 * integerDenominator);
Accuracy
There is no doubt that odd looking inaccuracies appear in floating point operations, but this is only when the numbers appear, and has little to do with rounding.
The source is not just the number of significant digits in the mantissa of the IEEE representation of a floating point number, it is related to our decimal thinking as humans.
Ten is the product of five and two, and 5 and 2 are relatively prime. Therefore the IEEE floating point standards cannot possibly be represented perfectly as decimal numbers for all binary digital representations.
This is not an issue with the rounding algorithms. It is mathematical reality that should be considered during the selection of types and the design of computations, data entry, and display of numbers. If an application displays the digits that show these decimal-binary conversion issues, then the application is visually expressing accuracy that does not exist in digital reality and should be changed.
You could round to n digits precision with:
double round( double x )
{
const double sd = 1000; //for accuracy to 3 decimal places
return int(x*sd + (x<0? -0.5 : 0.5))/sd;
}
Boost offers a simple set of rounding functions.
#include <boost/math/special_functions/round.hpp>
double a = boost::math::round(1.5); // Yields 2.0
int b = boost::math::iround(1.5); // Yields 2 as an integer
For more information, see the Boost documentation.
Edit: Since C++11, there are std::round
, std::lround
, and std::llround
.
If you ultimately want to convert the double
output of your round()
function to an int
, then the accepted solutions of this question will look something like:
int roundint(double r) {
return (int)((r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5));
}
This clocks in at around 8.88 ns on my machine when passed in uniformly random values.
The below is functionally equivalent, as far as I can tell, but clocks in at 2.48 ns on my machine, for a significant performance advantage:
int roundint (double r) {
int tmp = static_cast<int> (r);
tmp += (r-tmp>=.5) - (r-tmp<=-.5);
return tmp;
}
Among the reasons for the better performance is the skipped branching.
It's usually implemented as floor(value + 0.5)
.
Edit: and it's probably not called round since there are at least three rounding algorithms I know of: round to zero, round to closest integer, and banker's rounding. You are asking for round to closest integer.
The C++03 standard relies on the C90 standard for what the standard calls the Standard C Library which is covered in the draft C++03 standard (closest publicly available draft standard to C++03 is N1804) section 1.2
Normative references:
The library described in clause 7 of ISO/IEC 9899:1990 and clause 7 of ISO/IEC 9899/Amd.1:1995 is hereinafter called the Standard C Library.1)
If we go to the C documentation for round, lround, llround on cppreference we can see that round and related functions are part of C99 and thus won't be available in C++03 or prior.
In C++11 this changes since C++11 relies on the C99 draft standard for C standard library and therefore provides std::round and for integral return types std::lround, std::llround :
#include <iostream>
#include <cmath>
int main()
{
std::cout << std::round( 0.4 ) << " " << std::lround( 0.4 ) << " " << std::llround( 0.4 ) << std::endl ;
std::cout << std::round( 0.5 ) << " " << std::lround( 0.5 ) << " " << std::llround( 0.5 ) << std::endl ;
std::cout << std::round( 0.6 ) << " " << std::lround( 0.6 ) << " " << std::llround( 0.6 ) << std::endl ;
}
Another option also from C99 would be std::trunc which:
Computes nearest integer not greater in magnitude than arg.
#include <iostream>
#include <cmath>
int main()
{
std::cout << std::trunc( 0.4 ) << std::endl ;
std::cout << std::trunc( 0.9 ) << std::endl ;
std::cout << std::trunc( 1.1 ) << std::endl ;
}
If you need to support non C++11 applications your best bet would be to use boost round, iround, lround, llround or boost trunc.
Rolling your own version of round is hard
Rolling your own is probably not worth the effort as Harder than it looks: rounding float to nearest integer, part 1, Rounding float to nearest integer, part 2 and Rounding float to nearest integer, part 3 explain:
For example a common roll your implementation using std::floor
and adding 0.5
does not work for all inputs:
double myround(double d)
{
return std::floor(d + 0.5);
}
One input this will fail for is 0.49999999999999994
, (see it live).
Another common implementation involves casting a floating point type to an integral type, which can invoke undefined behavior in the case where the integral part can not be represented in the destination type. We can see this from the draft C++ standard section 4.9
Floating-integral conversions which says (emphasis mine):
A prvalue of a floating point type can be converted to a prvalue of an integer type. The conversion truncates; that is, the fractional part is discarded. The behavior is undefined if the truncated value cannot be represented in the destination type.[...]
For example:
float myround(float f)
{
return static_cast<float>( static_cast<unsigned int>( f ) ) ;
}
Given std::numeric_limits<unsigned int>::max()
is 4294967295
then the following call:
myround( 4294967296.5f )
will cause overflow, (see it live).
We can see how difficult this really is by looking at this answer to Concise way to implement round() in C? which referencing newlibs version of single precision float round. It is a very long function for something which seems simple. It seems unlikely that anyone without intimate knowledge of floating point implementations could correctly implement this function:
float roundf(x)
{
int signbit;
__uint32_t w;
/* Most significant word, least significant word. */
int exponent_less_127;
GET_FLOAT_WORD(w, x);
/* Extract sign bit. */
signbit = w & 0x80000000;
/* Extract exponent field. */
exponent_less_127 = (int)((w & 0x7f800000) >> 23) - 127;
if (exponent_less_127 < 23)
{
if (exponent_less_127 < 0)
{
w &= 0x80000000;
if (exponent_less_127 == -1)
/* Result is +1.0 or -1.0. */
w |= ((__uint32_t)127 << 23);
}
else
{
unsigned int exponent_mask = 0x007fffff >> exponent_less_127;
if ((w & exponent_mask) == 0)
/* x has an integral value. */
return x;
w += 0x00400000 >> exponent_less_127;
w &= ~exponent_mask;
}
}
else
{
if (exponent_less_127 == 128)
/* x is NaN or infinite. */
return x + x;
else
return x;
}
SET_FLOAT_WORD(x, w);
return x;
}
On the other hand if none of the other solutions are usable newlib could potentially be an option since it is a well tested implementation.
If you need to be able to compile code in environments that support the C++11 standard, but also need to be able to compile that same code in environments that don't support it, you could use a function macro to choose between std::round() and a custom function for each system. Just pass -DCPP11
or /DCPP11
to the C++11-compliant compiler (or use its built-in version macros), and make a header like this:
// File: rounding.h
#include <cmath>
#ifdef CPP11
#define ROUND(x) std::round(x)
#else /* CPP11 */
inline double myRound(double x) {
return (x >= 0.0 ? std::floor(x + 0.5) : std::ceil(x - 0.5));
}
#define ROUND(x) myRound(x)
#endif /* CPP11 */
For a quick example, see http://ideone.com/zal709 .
This approximates std::round() in environments that aren't C++11-compliant, including preservation of the sign bit for -0.0. It may cause a slight performance hit, however, and will likely have issues with rounding certain known "problem" floating-point values such as 0.49999999999999994 or similar values.
Alternatively, if you have access to a C++11-compliant compiler, you could just grab std::round() from its <cmath>
header, and use it to make your own header that defines the function if it's not already defined. Note that this may not be an optimal solution, however, especially if you need to compile for multiple platforms.
As pointed out in comments and other answers, the ISO C++ standard library did not add round()
until ISO C++11, when this function was pulled in by reference to the ISO C99 standard math library.
For positive operands in [½, ub] round(x) == floor (x + 0.5)
, where ub is 223 for float
when mapped to IEEE-754 (2008) binary32
, and 252 for double
when it is mapped to IEEE-754 (2008) binary64
. The numbers 23 and 52 correspond to the number of stored mantissa bits in these two floating-point formats. For positive operands in [+0, ½) round(x) == 0
, and for positive operands in (ub, +8] round(x) == x
. As the function is symmetric about the x-axis, negative arguments x
can be handled according to round(-x) == -round(x)
.
This leads to the compact code below. It compiles into a reasonable number of machine instructions across various platforms. I observed the most compact code on GPUs, where my_roundf()
requires about a dozen instructions. Depending on processor architecture and toolchain, this floating-point based approach could be either faster or slower than the integer-based implementation from newlib referenced in a different answer.
I tested my_roundf()
exhaustively against the newlib roundf()
implementation using Intel compiler version 13, with both /fp:strict
and /fp:fast
. I also checked that the newlib version matches the roundf()
in the mathimf
library of the Intel compiler. Exhaustive testing is not possible for double-precision round()
, however the code is structurally identical to the single-precision implementation.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
float my_roundf (float x)
{
const float half = 0.5f;
const float one = 2 * half;
const float lbound = half;
const float ubound = 1L << 23;
float a, f, r, s, t;
s = (x < 0) ? (-one) : one;
a = x * s;
t = (a < lbound) ? x : s;
f = (a < lbound) ? 0 : floorf (a + half);
r = (a > ubound) ? x : (t * f);
return r;
}
double my_round (double x)
{
const double half = 0.5;
const double one = 2 * half;
const double lbound = half;
const double ubound = 1ULL << 52;
double a, f, r, s, t;
s = (x < 0) ? (-one) : one;
a = x * s;
t = (a < lbound) ? x : s;
f = (a < lbound) ? 0 : floor (a + half);
r = (a > ubound) ? x : (t * f);
return r;
}
uint32_t float_as_uint (float a)
{
uint32_t r;
memcpy (&r, &a, sizeof(r));
return r;
}
float uint_as_float (uint32_t a)
{
float r;
memcpy (&r, &a, sizeof(r));
return r;
}
float newlib_roundf (float x)
{
uint32_t w;
int exponent_less_127;
w = float_as_uint(x);
/* Extract exponent field. */
exponent_less_127 = (int)((w & 0x7f800000) >> 23) - 127;
if (exponent_less_127 < 23) {
if (exponent_less_127 < 0) {
/* Extract sign bit. */
w &= 0x80000000;
if (exponent_less_127 == -1) {
/* Result is +1.0 or -1.0. */
w |= ((uint32_t)127 << 23);
}
} else {
uint32_t exponent_mask = 0x007fffff >> exponent_less_127;
if ((w & exponent_mask) == 0) {
/* x has an integral value. */
return x;
}
w += 0x00400000 >> exponent_less_127;
w &= ~exponent_mask;
}
} else {
if (exponent_less_127 == 128) {
/* x is NaN or infinite so raise FE_INVALID by adding */
return x + x;
} else {
return x;
}
}
x = uint_as_float (w);
return x;
}
int main (void)
{
uint32_t argi, resi, refi;
float arg, res, ref;
argi = 0;
do {
arg = uint_as_float (argi);
ref = newlib_roundf (arg);
res = my_roundf (arg);
resi = float_as_uint (res);
refi = float_as_uint (ref);
if (resi != refi) { // check for identical bit pattern
printf ("!!!! arg=%08x res=%08x ref=%08x\n", argi, resi, refi);
return EXIT_FAILURE;
}
argi++;
} while (argi);
return EXIT_SUCCESS;
}
// Convert the float to a string
// We might use stringstream, but it looks like it truncates the float to only
//5 decimal points (maybe that's what you want anyway =P)
float MyFloat = 5.11133333311111333;
float NewConvertedFloat = 0.0;
string FirstString = " ";
string SecondString = " ";
stringstream ss (stringstream::in | stringstream::out);
ss << MyFloat;
FirstString = ss.str();
// Take out how ever many decimal places you want
// (this is a string it includes the point)
SecondString = FirstString.substr(0,5);
//whatever precision decimal place you want
// Convert it back to a float
stringstream(SecondString) >> NewConvertedFloat;
cout << NewConvertedFloat;
system("pause");
It might be an inefficient dirty way of conversion but heck, it works lol. And it's good, because it applies to the actual float. Not just affecting the output visually.
Function double round(double)
with the use of the modf
function:
double round(double x)
{
using namespace std;
if ((numeric_limits<double>::max() - 0.5) <= x)
return numeric_limits<double>::max();
if ((-1*std::numeric_limits<double>::max() + 0.5) > x)
return (-1*std::numeric_limits<double>::max());
double intpart;
double fractpart = modf(x, &intpart);
if (fractpart >= 0.5)
return (intpart + 1);
else if (fractpart >= -0.5)
return intpart;
else
return (intpart - 1);
}
To be compile clean, includes "math.h" and "limits" are necessary. The function works according to a following rounding schema:
These days it shouldn't be a problem to use a C++11 compiler which includes a C99/C++11 math library. But then the question becomes: which rounding function do you pick?
C99/C++11 round()
is often not actually the rounding function you want. It uses a funky rounding mode that rounds away from 0 as a tie-break on half-way cases (+-xxx.5000
). If you do specifically want that rounding mode, or you're targeting a C++ implementation where round()
is faster than rint()
, then use it (or emulate its behaviour with one of the other answers on this question which took it at face value and carefully reproduced that specific rounding behaviour.)
round()
's rounding is different from the IEEE754 default round to nearest mode with even as a tie-break. Nearest-even avoids statistical bias in the average magnitude of numbers, but does bias towards even numbers.
There are two math library rounding functions that use the current default rounding mode: std::nearbyint()
and std::rint()
, both added in C99/C++11, so they're available any time std::round()
is. The only difference is that nearbyint
never raises FE_INEXACT.
Prefer rint()
for performance reasons: gcc and clang both inline it more easily, but gcc never inlines nearbyint()
(even with -ffast-math
)
I put some test functions on Matt Godbolt's Compiler Explorer, where you can see source + asm output (for multiple compilers). For more about reading compiler output, see this Q&A, and Matt's CppCon2017 talk: “What Has My Compiler Done for Me Lately? Unbolting the Compiler's Lid”,
In FP code, it's usually a big win to inline small functions. Especially on non-Windows, where the standard calling convention has no call-preserved registers, so the compiler can't keep any FP values in XMM registers across a call
. So even if you don't really know asm, you can still easily see whether it's just a tail-call to the library function or whether it inlined to one or two math instructions. Anything that inlines to one or two instructions is better than a function call (for this particular task on x86 or ARM).
On x86, anything that inlines to SSE4.1 roundsd
can auto-vectorize with SSE4.1 roundpd
(or AVX vroundpd
). (FP->integer conversions are also available in packed SIMD form, except for FP->64-bit integer which requires AVX512.)
std::nearbyint()
:
-msse4.1
.-msse4.1 -ffast-math
, and only on gcc 5.4 and earlier. Later gcc never inlines it (maybe they didn't realize that one of the immediate bits can suppress the inexact exception? That's what clang uses, but older gcc uses the same immediate as for rint
when it does inline it)std::rint
:
-msse4.1
-msse4.1
. (Without SSE4.1, inlines to several instructions)-ffast-math -msse4.1
.std::round
:
-ffast-math -msse4.1
, requiring two vector constants.std::floor
/ std::ceil
/ std::trunc
-msse4.1
-msse4.1
-ffast-math -msse4.1
int
/ long
/ long long
:You have two options here: use lrint
(like rint
but returns long
, or long long
for llrint
), or use an FP->FP rounding function and then convert to an integer type the normal way (with truncation). Some compilers optimize one way better than the other.
long l = lrint(x);
int i = (int)rint(x);
Note that int i = lrint(x)
converts float
or double
-> long
first, and then truncates the integer to int
. This makes a difference for out-of-range integers: Undefined Behaviour in C++, but well-defined for the x86 FP -> int instructions (which the compiler will emit unless it sees the UB at compile time while doing constant propagation, then it's allowed to make code that breaks if it's ever executed).
On x86, an FP->integer conversion that overflows the integer produces INT_MIN
or LLONG_MIN
(a bit-pattern of 0x8000000
or the 64-bit equivalent, with just the sign-bit set). Intel calls this the "integer indefinite" value. (See the cvttsd2si
manual entry, the SSE2 instruction that converts (with truncation) scalar double to signed integer. It's available with 32-bit or 64-bit integer destination (in 64-bit mode only). There's also a cvtsd2si
(convert with current rounding mode), which is what we'd like the compiler to emit, but unfortunately gcc and clang won't do that without -ffast-math
.
Also beware that FP to/from unsigned
int / long is less efficient on x86 (without AVX512). Conversion to 32-bit unsigned on a 64-bit machine is pretty cheap; just convert to 64-bit signed and truncate. But otherwise it's significantly slower.
x86 clang with/without -ffast-math -msse4.1
: (int/long)rint
inlines to roundsd
/ cvttsd2si
. (missed optimization to cvtsd2si
). lrint
doesn't inline at all.
x86 gcc6.x and earlier without -ffast-math
: neither way inlines
-ffast-math
: (int/long)rint
rounds and converts separately (with 2 total instructions of SSE4.1 is enabled, otherwise with a bunch of code inlined for rint
without roundsd
). lrint
doesn't inline.x86 gcc with -ffast-math
: all ways inline to cvtsd2si
(optimal), no need for SSE4.1.
AArch64 gcc6.3 without -ffast-math
: (int/long)rint
inlines to 2 instructions. lrint
doesn't inline
-ffast-math
: (int/long)rint
compiles to a call to lrint
. lrint
doesn't inline. This may be a missed optimization unless the two instructions we get without -ffast-math
are very slow.A certain type of rounding is also implemented in Boost:
#include <iostream>
#include <boost/numeric/conversion/converter.hpp>
template<typename T, typename S> T round2(const S& x) {
typedef boost::numeric::conversion_traits<T, S> Traits;
typedef boost::numeric::def_overflow_handler OverflowHandler;
typedef boost::numeric::RoundEven<typename Traits::source_type> Rounder;
typedef boost::numeric::converter<T, S, Traits, OverflowHandler, Rounder> Converter;
return Converter::convert(x);
}
int main() {
std::cout << round2<int, double>(0.1) << ' ' << round2<int, double>(-0.1) << ' ' << round2<int, double>(-0.9) << std::endl;
}
Note that this works only if you do a to-integer conversion.
Based on Kalaxy's response, the following is a templated solution that rounds any floating point number to the nearest integer type based on natural rounding. It also throws an error in debug mode if the value is out of range of the integer type, thereby serving roughly as a viable library function.
// round a floating point number to the nearest integer
template <typename Arg>
int Round(Arg arg)
{
#ifndef NDEBUG
// check that the argument can be rounded given the return type:
if (
(Arg)std::numeric_limits<int>::max() < arg + (Arg) 0.5) ||
(Arg)std::numeric_limits<int>::lowest() > arg - (Arg) 0.5)
)
{
throw std::overflow_error("out of bounds");
}
#endif
return (arg > (Arg) 0.0) ? (int)(r + (Arg) 0.5) : (int)(r - (Arg) 0.5);
}
I use the following implementation of round in asm for x86 architecture and MS VS specific C++:
__forceinline int Round(const double v)
{
int r;
__asm
{
FLD v
FISTP r
FWAIT
};
return r;
}
UPD: to return double value
__forceinline double dround(const double v)
{
double r;
__asm
{
FLD v
FRNDINT
FSTP r
FWAIT
};
return r;
}
Output:
dround(0.1): 0.000000000000000
dround(-0.1): -0.000000000000000
dround(0.9): 1.000000000000000
dround(-0.9): -1.000000000000000
dround(1.1): 1.000000000000000
dround(-1.1): -1.000000000000000
dround(0.49999999999999994): 0.000000000000000
dround(-0.49999999999999994): -0.000000000000000
dround(0.5): 0.000000000000000
dround(-0.5): -0.000000000000000
A certain type of rounding is also implemented in Boost:
#include <iostream>
#include <boost/numeric/conversion/converter.hpp>
template<typename T, typename S> T round2(const S& x) {
typedef boost::numeric::conversion_traits<T, S> Traits;
typedef boost::numeric::def_overflow_handler OverflowHandler;
typedef boost::numeric::RoundEven<typename Traits::source_type> Rounder;
typedef boost::numeric::converter<T, S, Traits, OverflowHandler, Rounder> Converter;
return Converter::convert(x);
}
int main() {
std::cout << round2<int, double>(0.1) << ' ' << round2<int, double>(-0.1) << ' ' << round2<int, double>(-0.9) << std::endl;
}
Note that this works only if you do a to-integer conversion.
It's usually implemented as floor(value + 0.5)
.
Edit: and it's probably not called round since there are at least three rounding algorithms I know of: round to zero, round to closest integer, and banker's rounding. You are asking for round to closest integer.
Function double round(double)
with the use of the modf
function:
double round(double x)
{
using namespace std;
if ((numeric_limits<double>::max() - 0.5) <= x)
return numeric_limits<double>::max();
if ((-1*std::numeric_limits<double>::max() + 0.5) > x)
return (-1*std::numeric_limits<double>::max());
double intpart;
double fractpart = modf(x, &intpart);
if (fractpart >= 0.5)
return (intpart + 1);
else if (fractpart >= -0.5)
return intpart;
else
return (intpart - 1);
}
To be compile clean, includes "math.h" and "limits" are necessary. The function works according to a following rounding schema:
I use the following implementation of round in asm for x86 architecture and MS VS specific C++:
__forceinline int Round(const double v)
{
int r;
__asm
{
FLD v
FISTP r
FWAIT
};
return r;
}
UPD: to return double value
__forceinline double dround(const double v)
{
double r;
__asm
{
FLD v
FRNDINT
FSTP r
FWAIT
};
return r;
}
Output:
dround(0.1): 0.000000000000000
dround(-0.1): -0.000000000000000
dround(0.9): 1.000000000000000
dround(-0.9): -1.000000000000000
dround(1.1): 1.000000000000000
dround(-1.1): -1.000000000000000
dround(0.49999999999999994): 0.000000000000000
dround(-0.49999999999999994): -0.000000000000000
dround(0.5): 0.000000000000000
dround(-0.5): -0.000000000000000
Since C++ 11 simply:
#include <cmath>
std::round(1.1)
or to get int
static_cast<int>(std::round(1.1))
// Convert the float to a string
// We might use stringstream, but it looks like it truncates the float to only
//5 decimal points (maybe that's what you want anyway =P)
float MyFloat = 5.11133333311111333;
float NewConvertedFloat = 0.0;
string FirstString = " ";
string SecondString = " ";
stringstream ss (stringstream::in | stringstream::out);
ss << MyFloat;
FirstString = ss.str();
// Take out how ever many decimal places you want
// (this is a string it includes the point)
SecondString = FirstString.substr(0,5);
//whatever precision decimal place you want
// Convert it back to a float
stringstream(SecondString) >> NewConvertedFloat;
cout << NewConvertedFloat;
system("pause");
It might be an inefficient dirty way of conversion but heck, it works lol. And it's good, because it applies to the actual float. Not just affecting the output visually.
Source: Stackoverflow.com