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
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))
from : http://www.cs.tut.fi/~jkorpela/round.html
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.
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);
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;
}
}
// 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.