Rounding Numbers In C++

Ever wanted some handy functions to round those pesky floating point values to whole integers?

In C# you can use the Math.Round() method which has more than half a dozen overloads supporting different data types and parameters to specify the rounding technique used.

In C++ there isn’t a std::round() equivalent, so let’s take a look at the options…

A simple cast to a non floating point type just truncates. That is, it keeps the bit to the left of the decimal point and throws away the bit on the other side. Often that’s undesirable. Even if you want to always round down, truncating isn’t doing what you’d like.

Consider this code:

double d1 = 5.7;
int i1 = (int)d1;		// i1 = 5

double d2 = -5.7;
int i2 = (int)d2;		// i2 = -5

The value 5.7 is truncated to 5 when it is cast to an int. Conversely, the value -5.7 is truncated to -5. In the first instance, the truncated value is less than the starting value. In the latter case, the truncated value is more. This can have weird properties when you’re trying to make code that behaves consistently.

If we actually want to always round down then this function from the std library will do the trick:

#include <math>
std::floor(n);

So for example, std::floor(5.7) yields 5. std::floor(-5.7) yields -6.

If on the other hand, we want to consistently round up, then this standard library function is the ticket:

#include <math>
std::ceil(n);

std::ceil(5.7) = 6. std::ceil(-5.7) = -5.

Those are simple, but what if we want to always round the value so that it approaches zero? IN other words, 5.7 will round down, whilst -5.7 will round up. This little template will do the trick:

template<typename T>
static T RoundTowardZero(T n)
{
	return (n > 0.0) ? std::floor(n) : std::ceil(n);
}

Here we use the ternary operator to evaluate whether the value is above zero. If it is, we use our round down method, if it isn’t we round up. The function is a template so we can use the same code on floating point values, doubles or any user defined class that it would make sense to round.

The method to always round away from zero follows directly:

template<typename T>
static T RoundAwayFromZero(T n)
{
	return (n > 0.0) ? std::ceil(n) : std::floor(n);
}

This version will round 5.7 up to 6 and will round -5.7 down to -6.

The final and perhaps most useful rounding function that I will present is the “classic round”, which rounds values away from zero when the decimal part is greater than or equal to 0.5, and it rounds towards zero when the decimal part is less than 0.5.

template<typename T>
static T Round(T n)
{
    return (n > 0.0) ? std::floor(n + 0.5) : std::ceil(n - 0.5);
}

There are lots of rounding solutions floating about on the internet, but it’s nice to have a bunch of them in your toolbox for a rainy day.

Here’s a full listing of all the functions, with floor and ceil wrapped up in functions called RoundDown and RoundUp for consistency.

#include <math>

template<typename T>
static T Round(T n)
{
    return (n > 0.0) ? std::floor(n + 0.5) : std::ceil(n - 0.5);
}

template<typename T>
static T RoundTowardZero(T n)
{
	return (n > 0.0) ? std::floor(n) : std::ceil(n);
}

template<typename T>
static T RoundAwayFromZero(T n)
{
	return (n > 0.0) ? std::ceil(n) : std::floor(n);
}

template<typename T>
static T RoundUp(T n)
{
	return std::ceil(n);
}

template<typename T>
static T RoundDown(T n)
{
	return std::floor(n);
}