round() for float in C++
Solution 1
It's available since C++11 in cmath (according to http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf)
#include <cmath>
#include <iostream>
int main(int argc, char** argv) {
std::cout << "round(0.5):\t" << round(0.5) << std::endl;
std::cout << "round(-0.5):\t" << round(-0.5) << std::endl;
std::cout << "round(1.4):\t" << round(1.4) << std::endl;
std::cout << "round(-1.4):\t" << round(-1.4) << std::endl;
std::cout << "round(1.6):\t" << round(1.6) << std::endl;
std::cout << "round(-1.6):\t" << round(-1.6) << std::endl;
return 0;
}
Output:
round(0.5): 1
round(-0.5): -1
round(1.4): 1
round(-1.4): -1
round(1.6): 2
round(-1.6): -2
Solution 2
Editor's Note: The following answer provides a simplistic solution that contains several implementation flaws (see Shafik Yaghmour's answer for a full explanation). Note that C++11 includes
std::round
,std::lround
, andstd::llround
as builtins already.
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.
Solution 3
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
.
Solution 4
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.
Solution 5
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);
}
Related videos on Youtube
Roddy
Updated on January 19, 2022Comments
-
Roddy over 2 years
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()
andfloor()
in the math.h - but notround()
.Is it present in the standard C++ library under another name, or is it missing??
-
Frank about 13 yearsIf you just want to output the number as a rounded number it seems you can just do
std::cout << std::fixed << std::setprecision(0) << -0.9
, for example. -
Shog9 about 13 yearsProtecting this... New users with brilliant new rounding schemes should read existing answers first.
-
Alessandro Jacopson about 11 years
round
is available since C++11 in<cmath>
. Unfortunately if you are in Microsoft Visual Studio it is still missing: connect.microsoft.com/VisualStudio/feedback/details/775474/… -
Shafik Yaghmour almost 10 yearsAs I note in my answer, rolling your own
round
has a lot of caveats. Before C++11, the standard relied on C90 which did not includeround
. C++11 relies on C99 which does haveround
but also as I noted includestrunc
which has different properties and may be more appropriate depending on the application. Most answers also seem to ignore that a user may wish to return an integral type which has even more issues. -
Shafik Yaghmour almost 10 years@uvts_cvs this does not seem to be an issue with the latest version of visual studio, see it live.
-
Alessandro Jacopson almost 10 years@ShafikYaghmour you are right, Microsoft declare it as "Closed as Fixed" but without info about the release of MSVC or the date of the fix :-(
-
simplename about 2 yearsfor basic usage, simply
static_cast<int>(std::round(0.1))
, for more details there are the answers
-
-
xtofl over 15 yearsIt's good to make the distinction between different versions of 'round'. It's good to know when to pick which, too.
-
Registered User almost 15 yearsThis doesn't handle negative numbers correctly. The answer by litb is correct.
-
Roddy almost 15 years@InnerJoin: Yes, it handles negative numbers differently to litb's answer, but that doesn't make it "incorrect".
-
Lazer almost 14 yearsWhat if you want to round to some places after the decimal precision? multiply and divide?
-
Andreas Magnusson almost 14 years@Lazer: I would be careful to mul-div floating-point values. There's no guarantee that (f * 10) / 10 == f for a floating-point value. That said, a mul-div is probably the easiest way to achieve it...
-
Daniel Wolf about 13 yearsBoost also offers a set of simple rounding functions; see my answer.
-
aka.nice almost 12 yearsUnless your compiler int size defaults to 1024 bits, this ain't gonna be accurate for huge double...
-
Carl almost 12 yearsI think that is acceptable given when it will be used: If your double value is 1.0 e+19, rounding out to 3 places doesn't make sense.
-
aka.nice almost 12 yearssure, but the question is for a generic round, and you can't control how it will be used. There is no reason for round to fail where ceil and floor would not.
-
aka.nice almost 12 yearsThis is a good solution. I'm not sure that rounding -1.5 to -1.0 is standard though, I would expect -2.0 by symetry. Also I don't see the point of the leading guard, the first two if could be removed.
-
aka.nice almost 12 yearsI checked in ISO/IEC 10967-2 standard, open-std.org/jtc1/sc22/wg11/docs/n462.pdf and from appendix B.5.2.4, the rounding function must indeed be symmetric, rounding_F(x) = neg_F(rounding_F(neg_F(x)))
-
Pete855217 over 11 yearsDidn't you mean pow(10,place) rather than the binary operator ^ in 10^place? 10^2 on my machine gives me 8!! Nevertheless on my Mac 10.7.4 and gcc, the code doesn't work, returning the original value.
-
Pascal Cuoq almost 11 yearsAdding 0.5 before truncating fails to round to the nearest integer for several inputs including 0.49999999999999994. See blog.frama-c.com/index.php?post/2013/05/02/nearbyintf1
-
Sergi0 over 10 years@Roddy no, the fact that it rounds negative numbers incorrect makes it incorrect.
-
Waihon Yew over 10 years@Sergi0: There is no "correct" and "incorrect" because there are more than one definitions of rounding that decide what happens at the halfway point. Check your facts before passing judgement.
-
stijn over 10 yearsDoes not give the expected result for 0.49999999999999994 though (well, depending on what you expect of course, but 0 seems more reasonable to me than 1)
-
stijn over 10 yearsYou can also use
boost:numeric::RoundEven< double >::nearbyint
directly if you don't want to-integer. @DanielWolf note that the simple function is implemented using +0.5 which has problems as layed out by aka.nice -
kalaxy over 10 years@stijn Good catch. I found that adding the long double literal suffix to my constants fixed your example issue, but I don't know if there are other precision examples that it wouldn't catch.
-
stijn over 10 yearssee aka.nice's answer and the links provided - try with 5000000000000001.0 for example
-
stijn over 10 yearsbtw if you add 0.49999999999999994 instead of 0.5, it does work ok for both 0.49999999999999994 and 5000000000000001.0 as input. Not sure if it is ok for all values though, and I couldn't find any reference stating that this is the ultimate fix.
-
Pascal Cuoq over 10 years@stijn It is ok for all values, if you do not care in which direction the values exactly in-between two integers are rounded. Without thinking, I would prove it by case analysis with the following cases: 0 <= d < 0.5, 0.5 <= d < 1.5, 1.5 <= d < 2^52, d >= 2^52. I also exhaustively tested the single-precision case.
-
Muhammad over 10 yearsyou can check
std::numeric_limits::round_style
for round style type and to implement your function for accurate result, in c++11 you should usestd::fegetround
to know round mode. see en.cppreference.com/w/cpp/types/numeric_limits/round_style and en.cppreference.com/w/cpp/numeric/fenv/feround -
SSpoke over 10 yearsVery important bug since it doesn't use
ceil
if you doround(-2.5)
it will give back-2
instead of-3
. -
Andreas Magnusson over 10 years@SSpoke: It rounds up to the nearest larger integer. -2 > -3. It's called "Round Half Up": en.wikipedia.org/wiki/Rounding#Round_half_up
-
Andreas Magnusson about 10 years@MuhammadAnnaqeeb: You're right, things have improved immensely since the release of C++11. This question was asked and answered in another time when life was hard and the joys were few. It remains here as an ode to heroes who lived and fought back then and for those poor souls who still are unable to use modern tools.
-
Gustavo Maciel almost 10 yearsI was already using boost in my project, +1 for this, much better than using the naïve
floor(value + 0.5)
approach! -
Shafik Yaghmour almost 10 years@Roddy considering Pascal Couq's three part article, which is in a comment above, on how tricky this operation is this answer is just not sufficient. Any answer that purports to roll your own would have to be very long indeed. The 20+ downvotes should also be a strong indication that something is wrong with this answer.
-
Shafik Yaghmour almost 10 yearsAs I pointed out in my answer adding
0.5
does not work in all cases. Although at least you deal with the overflow issue so you avoid undefined behavior. -
Shafik Yaghmour almost 10 years@downvoter please explain what can be improved? The vast majority of the answer here are just wrong since they attempt to roll their own round which all fail in one form or another. If there is something missing in my explanation please let me know.
-
aka.nice almost 10 yearsI'm interested to know about the downvotes. Is it because the tie is resolved away from zero rather than to nearest even?
-
truthseeker over 9 yearsResult value should be floating point value with double precision.
-
truthseeker over 9 yearsThe resulting value should be floating point value with double precision. Its not an answer for question asked.
-
Aleksey F. over 9 years@ truthseeker: Yeah, I had to see the required type of return value. OK, see "UPD".
-
sp2danny about 9 yearsthere is also
lround
andllround
for integral results -
Tony Delroy almost 9 yearsPer 4.9 [conv.fpint], "The behavior is undefined if the truncated value cannot be represented in the destination type.", so this is a little dangerous. Other SO answers describe how to do this robustly.
-
chux - Reinstate Monica over 8 yearsNice complete answer - especially the just below 0.5 part. Another niche:
round(-0.0)
. C spec does not appear to specify. I'd expect-0.0
as a result. -
chux - Reinstate Monica over 8 yearsNote: the C spec says "rounding halfway cases away from zero, regardless of the current rounding direction.", so rounding without regard to odd/even is compliant.
-
Ruslan about 8 years@chux interesting, and IEEE 754-2008 standard does specify that rounding preserves signs of zeros and infinities (see 5.9).
-
Ruslan about 8 years@Shafik this is a great answer. I've never thought that even rounding is a non-trivial operation.
-
Bruce Dawson almost 8 yearsThere are indeed different rounding algorithms which can all make reasonable claims to being "correct". However floor(value + 0.5) is not one of these. For some values, such as 0.49999997f or the equivalent double, the answer is just wrong - it will be rounded to 1.0 when all agree that it should be zero. See this post for details: blog.frama-c.com/index.php?post/2013/05/02/nearbyintf1
-
chux - Reinstate Monica over 7 yearsUsing
LONG_MIN-0.5
andLONG_MAX+0.5
introduces complications as the math may not be exact.LONG_MAX
may exceeddouble
precision for exact conversion. Further likely wantassert(x < LONG_MAX+0.5);
(< vs <=) asLONG_MAX+0.5
may be exactly representable and(x)+0.5
may have an exact result ofLONG_MAX+1
which failslong
cast. Other corner issues too. -
Aaron3468 over 7 years@Jon You're partially correct. The three major types of rounding are floor, ceiling, and truncation, with the term round often reserved specifically as a synonym of truncation. Given the ubiquity of the prior 3 rounding functions, I'd expect a standard math library in any language to support their use (as many do). Anything beyond those lies in the realm where I would not fault language designers for expecting users to design specialized libraries; most languages are general-purpose.
-
Douglas Daseeco almost 7 yearsThis function is incorrect for negative numbers. Furthermore, no one living on earth and connected to the Internet should be using libraries from the last century when backward and forward compatibility have been so carefully considered in the last 20 years. See stackoverflow.com/questions/485525/round-for-float-in-c/….
-
Peter Cordes over 6 years@sp2danny: or better,
lrint
to use the current rounding mode instead ofround
's funky away-from-zero tiebreak. -
Peter Cordes over 6 yearsPerhaps worth mentioning that
std::rint()
is often preferable tostd::round()
when C++11 is available for numeric and performance reasons. It uses the current rounding mode, unlikeround()
's special mode. It can be much more efficient on x86, whererint
can inline to a single instruction. (gcc and clang do that even without-ffast-math
godbolt.org/g/5UsL2e, while only clang inlines the nearly-equivalentnearbyint()
) ARM has single-instruction support forround()
, but on x86 it can only inline with multiple instructions, and only with-ffast-math
-
Peter Cordes over 6 yearsDon't call your function
round(double)
, there's already a standard math library function of that name (in C++11) so it's confusing. Usestd::lrint(x)
if it's available. -
Peter Cordes over 6 yearsThis has undefined behaviour for args outside the range of
int
. (In practice on x86, out-of-range FP values will makeCVTTSD2SI
produce0x80000000
as the integer bit pattern, i.e.INT_MIN
, which will then be converted back todouble
. -
Peter Cordes over 6 yearsThis has undefined behaviour for args outside the range of
int
. (In practice on x86, out-of-range FP values will makeCVTTSD2SI
produce0x80000000
as the integer bit pattern, i.e.INT_MIN
, which will then be converted back todouble
. -
Peter Cordes over 6 yearsThis is going to be slow compared to C++11
rint()
ornearbyint()
, but if you really can't use a compiler that provides a proper rounding function, and you need precision more than performance... -
Peter Cordes over 6 yearsThe compiler will hopefully inline
rint()
ornearbyint()
to an SSE4.1roundsd
instruction or an x87frndint
instruction, which will be much faster than the two store/reload round trips needed to use this inline asm on data in a register. MSVC inline asm sucks quite a lot for wrapping single instructions likefrndint
because there's no way to get the input in a register. Using it at the end of a function with the result inst(0)
might be reliable as a way of returning output; apparently that's safe foreax
for integers, even when it inlines the function containing the asm. -
Peter Cordes over 6 yearsI made an edit to avoid assuming
int
is more than 16 bits wide. It does still of course assume thatfloat
is 4-byte IEEE754 binary32. A C++11static_assert
or maybe a macro#ifdef
/#error
could check that. (But of course if C++11 is available, you should usestd::round
, or for the current rounding mode usestd::rint
which inlines nicely with gcc and clang). -
Peter Cordes over 6 yearsThis is hilariously inefficient, and also it truncates (by always discarding trailing digits) instead of rounding to nearest.
-
Peter Cordes over 6 yearsBTW,
gcc -ffast-math -msse4.1
inlinesstd::round()
to anadd( AND(x, L1), OR(x,L2)
, and then aroundsd
. i.e. it fairly efficiently implementsround
in terms ofrint
. But there's no reason to do this manually in C++ source, because if you havestd::rint()
orstd::nearbyint()
you also havestd::round()
. See my answer for a godbolt link and a rundown of what inlines or not with different gcc/clang versions. -
Peter Cordes over 6 yearsTODO: ICC and MSVC are also available on Godbolt, but I haven't looked at their output for this. edits welcome... Also: would it be more useful to break down by compiler / version first and then by function within that? Most people aren't going to switch compilers based on how well they compile FP->FP or FP->integer rounding.
-
jaggedSpire over 6 years"I'm not sure why so many answers involve defines, functions, or methods." Have a look at when it was asked--C++11 wasn't out yet. ;)
-
njuffa over 6 years@PeterCordes I am well aware how to implement
round()
efficiently in terms ofrint()
(when the latter is operating in mode round-to-nearest-or-even): I implemented that for the CUDA standard math library. However, this question seemed to ask how to implementround()
with C++ prior to C++11, sorint()
would not be available either, onlyfloor()
andceil()
. -
njuffa over 6 years+1 for recommending
rint()
where that is a feasible choice, which is usually the case. I guess the nameround()
implies to some programmers that this is what they want, whilerint()
seems mysterious. Note thatround()
doesn't use a "funky" rounding mode: round-to-nearest-ties-away is an official IEEE-754 (2008) rounding mode. It's curious thatnearbyint()
doesn't get inlined, given that it is largely the same asrint()
, and should be identical under-ffast-math
conditions. That looks bug-ish to me. -
njuffa over 6 years@PeterCordes Sorry, I misspoke.
round()
is easily synthesized fromrint()
in round-to-zero mode, a.k.a.trunc()
. Shouldn't have responded before first coffee. -
Peter Cordes over 6 yearsI was mostly commenting for other readers, and for shameless self-promotion of my answer because I think people are taking this question far too literally, and ignoring the "I need a simple floating point rounding function". The fact that the OP is hoping there is one called "round()" doesn't (to me) indicate that they specifically want the rounding behaviour of
std::round()
as opposed to the default / current rounding mode if that's more efficient. -
njuffa over 6 years@PeterCordes I agree that it is likely that OP doesn't need the specific rounding behavior of
round()
; most programmers simply aren't aware of the distinction betweenround()
vsrint()
with round-to-nearest-even, where the latter is usually provided directly by the hardware and therefore more efficient; I spelled that out in CUDA Programming Guide to make programmers aware: "The recommended way to round a single-precision floating-point operand to an integer, with the result being a single-precision floating-point number isrintf()
, notroundf()
". -
Aleksey F. over 6 years@PeterCordes Modern optimizations are welcome. However I was not able to use SSE4.1 as it did not exist at that moment. My purpose was to provide the minimal implementation of round which could function even on old Intel P3 or P4 families from 2000's.
-
Peter Cordes over 6 yearsP3 doesn't even have SSE2, so the compiler will already be using x87 for
double
, and thus should be able to emitfrndint
itself forrint()
. If your compiler is using SSE2, bouncing adouble
from an XMM register to x87 and back may not be worth it. -
n. m. over 6 years@GustavoMaciel I know I'm a bit late to the game, but boost implementation is
floor(value + 0.5)
. -
Gustavo Maciel over 6 yearsIt actually does not: github.com/boostorg/math/blob/develop/include/boost/math/… 4 years later, I'd also like to say that
floor(value + 0.5)
is not naive at all, but rather depend on the context and nature of values you want to round! -
Douglas Daseeco about 6 years@jaggedSpire, well give me a thumbs up then, if you feel it is appropriate, because all the high scoring answers are obsolete and misleading in the context of today's most commonly used compilers.
-
Shafik Yaghmour about 6 yearsAlso see this all integer implementation via this tweet
-
eri0o over 3 yearsBut how is it linked?