For a particular question, I need to perform calculations on a floating number, round it off to 2 digits after the decimal place, and assign it to a variable for comparison purposes. I tried to find a solution to this but all I keep finding is how to print those rounded numbers (using printf
or setprecision
) instead of assigning them to a variable.
Please help.

- 1
- 2
-
This is a C++ question, not a C question. Please remove the C tag. – mediocrevegetable1 Apr 03 '21 at 06:46
-
3It is not actually possible to round numbers exactly to two decimal places in a binary-based floating-point format, except those that are multiples of ¼ (those that end in .00, .25, .50, or .75). And attempting to round to make a comparison is generally a bad idea, as rounding makes errors larger near the rounding points, not smaller. [There is no general solution for comparing floating-point numbers that contain errors from previous operations.](https://stackoverflow.com/a/21261885/298225) For a solution specific to your problem, you should explain the context of your problem. – Eric Postpischil Apr 03 '21 at 11:51
-
1By chance are you calculating something that represents a monetary amount? If so, have you considered converting from dollars with a decimal point to absolute cents (as an integer). – selbie Apr 03 '21 at 16:11
-
@selbie Basing computations based on cents is not going to cut it. The smallest division of a dollar commonly in use (e.g. gasoline prices) is the mill, or 1/1000 of a dollar. Even using that as the basic unit may not be sufficient, as point out in [this answer](https://stackoverflow.com/a/149050/780717), for example. – njuffa Apr 04 '21 at 01:47
-
1@njuffa: SEC rule 612 sets $0.0001 as the increment for prices of stocks under $1/share. – Eric Postpischil Apr 04 '21 at 02:30
-
@EricPostpischil Another example I shall add to my list of random numerical factoids :-) – njuffa Apr 04 '21 at 04:15
3 Answers
round it off to 2 digits after the decimal place, and assign it to a variable for comparison purposes
To avoid errors that creep in when using binary floating point in a decimal problem, consider alternatives.
Direct approach has corner errors due to double rounding and overflow. These errors may be tolerable for OP larger goals
// Errors:
// 1) x*100.0, round(x*100.0)/100.0 inexact.
// Select `x` values near "dddd.dd5" form an inexact product `x*100.0`
// and may lead to a double rounding error and then incorrect result when comparing.
// 2) x*100.0 may overflow.
int compare_hundredth1(double x, double ref) {
x = round(x*100.0)/100.0;
return (x > ref) - (x < ref);
}
We can do better.
When a wider floating point type exist:
int compare_hundredth2(double x, double ref) {
auto x_rounded = math::round(x*100.0L);
auto ref_rounded = ref*100.0L;
return (x_rounded > ref_rounded) - (x_rounded < ref_rounded);
}
To use the same width floating point type takes more work:
All finite large values of x, ref
are whole numbers and need no rounding to the nearest 0.01.
int compare_hundredth3(double x, double ref) {
double x_whole;
auto x_fraction = modf(x, &x_whole);
// If rounding needed ...
if (x_fraction != 0.0) {
if (x - 0.01 > ref) return 1; // x much more than ref
if (x + 0.01 < ref) return -1; // x much less than ref
// x, ref nearly the same
double ref_whole;
auto ref_fraction = modf(x, &ref_whole);
x -= ref_whole;
auto x100 = (x - ref_whole)*100; // subtraction expected to be exact here.
auto ref100 = ref_fraction*100;
return (x100 > ref100) - (x100 < ref100);
}
return (x > ref) - (x < ref);
}
The above assume ref
is without error. If this is not so, consider using a scaled ref
.
Note: The above sets aside not-a-number concerns.
More clean-up later.

- 143,097
- 13
- 135
- 256
I usually do something like that:
#include <cmath> // 'std::floor'
#include <limits> // 'std::numeric_limits'
// Round value to granularity
template<typename T> inline T round(const T x, const T gran)
{
//static_assert(gran!=0);
return gran * std::floor( x/gran + std::numeric_limits<T>::round_error() );
}
double rounded_to_cent = round(1.23456, 0.01); // Gives something near 1.23
Be sure you know how floating point types work though.
Addendum: I know that this topic has already been extensively covered in other questions, but let me put this small paragraph here.
Given a real number, you can represent it with -almost- arbitrary accuracy with a (base10) literal like 1.2345
, that's a string that you can type with your keyboard.
When you store that value in a floating point type, let's say a double
, you -almost- always loose accuracy because probably your number won't have an exact representation in the finite set of the numbers representable by that type.
Nowadays double
uses 64 bits, so it has 2^64 symbols to represent the not numerable infinity of real numbers: that's a H2O molecule in an infinity of infinite oceans.
The representation error is relative to the value; for example in a IEEE 754 double, over 2^53 not all the integer values can be represented.
So when someone tells that the "result is wrong" they're technically right; the "acceptable" result is application dependent.

- 574
- 2
- 7
- 19
-
1This produces incorrect results. For example, for `round(0.104999996721744537353515625f, .01f)`, it rounds up to 0.10999999940395355224609375 (when the IEEE-754 32-bit “single” format is used with correct rounding), whereas the correct result is to round down to near .10 (the nearest representable value is 0.100000001490116119384765625). – Eric Postpischil Apr 03 '21 at 11:38
-
The use of `std::numeric_limits
::round_error()` is inappropriate. `round_error` describes the type of rounding that occurs in floating-point arithmetic. When round-to-nearest is in use, it is ½, to indicate the maximum rounding error is ½ ULP. When rounding modes such as toward-infinity or toward-zero are in use, it should be 1. While ½ is sort of suitable for the attempted (but incorrect) rounding intended here, the value of 1 would not make this work in other rounding modes. – Eric Postpischil Apr 03 '21 at 11:42 -
1The choice of `floor` is also odd, as this sort of rounding is usually preferred to be symmetric around zero. Instead of using `floor` and adding an incorrect symbolic constant, one could use a choice of `nearbyint` (to use the current rounding mode) or `round` (to round halfway cases away from zero). – Eric Postpischil Apr 03 '21 at 11:45
-
1The choice to express granularity directly instead of as its reciprocal makes it impossible to pass decimal granularities in a binary floating-point format. One-hundredth, .01, cannot be expressed exactly in a binary floating-point format. For example, passing `.01f` actually passes 0.00999999977648258209228515625. This will cause increasingly large errors with increasing inputs even if the code inside the routine used infinitely precise arithmetic. – Eric Postpischil Apr 03 '21 at 11:46
-
@EricPostpischil Floating point types are indeed a very slippery topic! Please post a proper reply, that would help the community – MatG Apr 03 '21 at 15:08
Here's an example with a custom function that rounds up the floating number f
to n
decimal places. Basically, it multiplies the floating number by 10 to the power of N to separate the decimal places, then uses roundf
to round the decimal places up or down, and finally divides back the floating number by 10 to the power of N (N is the amount of decimal places). Works for C and C++:
#include <stdio.h>
#include <math.h>
float my_round(float f, unsigned int n)
{
float p = powf(10.0f, (float)n);
f *= p;
f = roundf(f);
f /= p;
return f;
}
int main()
{
float f = 0.78901f;
printf("%f\n", f);
f = my_round(f, 2); /* Round with 2 decimal places */
printf("%f\n", f);
return 0;
}
Output:
0.789010
0.790000

- 144
- 10
-
this is not working when comparing equal floats. It gives true for 0.790000<0.79 – sudorohit Apr 03 '21 at 07:40
-
@sudorohit Please be careful about comparing float types, it's not so easy as it seems – MatG Apr 03 '21 at 10:20
-
2This gets incorrect results. For example, it rounds 0.104999996721744537353515625 up to 0.10999999940395355224609375 (when the IEEE-754 32-bit “single” format is used with correct rounding), whereas the correct result is to round down to near .10 (the nearest representable value is 0.100000001490116119384765625). – Eric Postpischil Apr 03 '21 at 11:31
-
@rdbo: The numbers I showed do not have too many decimal places to be printed, as proven by the fact that I printed them, using a C++ implementation. Any C++ implementation that uses the IEEE-754 32-bit binary format (or better) and correct rounding will print them. `printf` does not fail. You have to request more than the default number of digits displayed to see them all. The values represented are exactly the value I showed. 0.104999996721744537353515625, is exactly 14,092,861 / 2^27, which is why it is representable in `float`, and 0.100000001490116119384765625 is 13,421,773 / 2^27. – Eric Postpischil Apr 03 '21 at 15:39