32

I want to round a float number to a given precision, for example :

0.051 i want to convert it to
0.1

0.049 i want to convert it to
0.0

0.56 i want to convert it to
0.6

0.54 i want to convert it to
0.5

I cant explain it better, but the reason for this is to translate a point location (like 0.131f, 0.432f) to the location of tile in a grid (like 0.1f, 0.4f).

ivan_pozdeev
  • 33,874
  • 19
  • 107
  • 152
SteveL
  • 3,331
  • 4
  • 32
  • 57
  • 1
    Rounding a floating-point number to 1 or more decimal places doesn't make much sense; a number like `0.1` cannot be represented exactly in binary floating-point. Rounding can be done on output (to a string or to a file). – Keith Thompson Feb 18 '14 at 18:17
  • We are in the IT department ,we are trying to represent the infinite possibilities of the real world in lines of code, everything makes sense here. I am using this for a infinite scrolling background in a game, lost precision doesn't really matter. – SteveL Feb 18 '14 at 20:40
  • I have tested this, and it seems to not work correctly. If you try to round 127, it returns 128 (I am using double instead of float for f and for the return type). – Miguel Mesquita Alfaiate Aug 14 '14 at 11:42
  • @BlunT ,probably you didn't got the point of the function ,what is the precision you are passing? if you put 2 you will get 128 cause you will get the closest number from 0,2,4,6...,128,130...(2 as a increment),if you pass 127.456 and precision 0.01f you will get 127.46 cause 127.46 is the closest to 0,0.01,0.02f.....127.45,127.46,127.47(0.01 as an increment) – SteveL Aug 14 '14 at 12:48
  • @SteveL Well in that case you are correct, as the function rounds up to the nearest pair number, and I am using 2 as precision. Nonetheless, I think the title of the question might be misleading. In my opinion, and taking into account other implementations of round in other programming languages, precision refers to the number of decimal digits. – Miguel Mesquita Alfaiate Aug 14 '14 at 14:12
  • @BlunT ,Yea the title seems to be misleading but I could't find a better title at the time. – SteveL Aug 14 '14 at 14:20
  • @royv (if you come here) this question is not a duplicate of your question, I'd suggest un-deleting your question. This question actually modifies the float and also does not solve the display issue. Solving the display issue is a different matter and does not require modifying the float. – M.M Mar 16 '15 at 21:23
  • Rounding numbers inside the program does make sense if you lose precision and need to compare the result to something. Example, if you multiply a matrix (internally a double array) to its inverted you should get the identity matrix, but as you can lose precision inside the multiplication routine, you can get small numbers in places you should get zeroes. If you try to compare the result to a real identity matrix, you'll get a FALSE instead an expected TRUE. So rounding the multiplication result can be a good idea in this case. My way to round: `#define ROUND(n,p) round(n*pow(10,p))/pow(10,p)` – Vinícius A. Jorge Oct 14 '15 at 18:59

11 Answers11

26

As long as your grid is regular, just find a transformation from integers to this grid. So let's say your grid is

0.2  0.4  0.6  ...

Then you round by

float round(float f)
{
    return floor(f * 5 + 0.5) / 5;
    // return std::round(f * 5) / 5; // C++11
}
LogicStuff
  • 19,397
  • 6
  • 54
  • 74
marton78
  • 3,899
  • 2
  • 27
  • 38
9

The standard ceil(), floor() functions don't have a precision, I guess could work around that by adding your own precision - but this may introduce errors - e.g.

double ceil(double v, int p)
{
  v *= pow(10, p);
  v = ceil(v);
  v /= pow(10, p);
}

I guess you could test to see if this is reliable for you?

Nim
  • 33,299
  • 2
  • 62
  • 101
7

EDIT 1: I was looking for solutions for numpy in python and didn't realize that the OP asked for C++ haha, oh well.

EDIT 2: Lol, looks like I didn't even address your original question. It looks like you're really wanting to round off according to a decimal (operation is independent of the given number), not a precision (operation is dependent on the number), and the others have already addressed that.

I was actually looking around for this too but could not find something, so I threw together an implementation for numpy arrays. It looks like it implements the logic that slashmais stated.

def pround(x, precision = 5):
    temp = array(x)
    ignore = (temp == 0.)
    use = logical_not(ignore)
    ex = floor(log10(abs(temp[use]))) - precision + 1
    div = 10**ex
    temp[use] = floor(temp[use] / div + 0.5) * div
    return temp

Here's a C++ scalar version as well, and you could probably do something similar to above using Eigen (they have logical indexing): (I also took this as a chance to practice some more boost haha):

#include <cmath>
#include <iostream>
#include <vector>
#include <boost/foreach.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>

using namespace std;

double pround(double x, int precision)
{
    if (x == 0.)
        return x;
    int ex = floor(log10(abs(x))) - precision + 1;
    double div = pow(10, ex);
    return floor(x / div + 0.5) * div;
}

    template<typename T>
vector<T>& operator<<(vector<T> &x, const T &item)
{
    x.push_back(item);
    return x;
}

int main()
{
    vector<double> list;
    list << 0.051 << 0.049 << 0.56 << 0.54;
    // What the OP was wanting
    BOOST_FOREACH(double x, list)
    {
        cout << floor(x * 10 + 0.5) / 10 << "\n";
    }

    cout << "\n";

    BOOST_FOREACH(double x, list)
    {
        cout << pround(x, 0) << "\n";
    }

    cout << "\n";

    boost::function<double(double)> rounder = boost::bind(&pround, _1, 3);
    vector<double> newList;
    newList << 1.2345 << 1034324.23 << 0.0092320985;
    BOOST_FOREACH(double x, newList)
    {
        cout << rounder(x) << "\n";
    }

    return 0;
}

Output:

0.1
0
0.6
0.5

0.1
0
1
1

1.23
1.03e+06
0.00923
eacousineau
  • 3,457
  • 3
  • 34
  • 37
6

An algorithm you can use:

  • get 10-to-the-power(number-of-significant-digits) (=P10)
  • multiply your double-value by P10
  • add: 0.5 (or subtract if negative - see Ankush Shah's comment)
  • divide the integer-portion of this sum by (P10) - the answer will be your rounded number
slashmais
  • 7,069
  • 9
  • 54
  • 80
4

Use floor() and ceil(). floor will convert a float to the next smaller integer, and ceil to the next higher:

floor( 4.5 ); // returns 4.0
ceil( 4.5 );  // returns 5.0

I think the following would work:

float round( float f )
{   
    return floor((f * 10 ) + 0.5) / 10;
}

floor( f + 0.5 ) will round to an integer. By first multiplying by 10 and then dividing the result by 10 you are rounding by increments of 0.1.

Jongware
  • 22,200
  • 8
  • 54
  • 100
Rafael Baptista
  • 11,181
  • 5
  • 39
  • 59
  • What about negative floats? (I used to use this for positive floats before better std lib coverage.) – sage Jun 23 '16 at 22:48
3

Usually you know the desired precision at compile time. Therefore, using the templated Pow function available here, you can do:

template <int PRECISION>
float roundP(float f)
{
    const int temp = Pow<10,PRECISION>::result;
    return roundf(f*temp)/temp;
}

int main () {
    std::cout << std::setprecision(10);
    std::cout << roundP<0>(M_PI) << std::endl;
    std::cout << roundP<1>(M_PI) << std::endl;
    std::cout << roundP<2>(M_PI) << std::endl;
    std::cout << roundP<3>(M_PI) << std::endl;
    std::cout << roundP<4>(M_PI) << std::endl;
    std::cout << roundP<5>(M_PI) << std::endl;
    std::cout << roundP<6>(M_PI) << std::endl;
    std::cout << roundP<7>(M_PI) << std::endl;
}

Tested here.

The result also shows how imprecise is floating point representation :)

3

3.099999905

3.140000105

3.14199996

3.141599894

3.141590118

3.141592979

3.141592741

You can have better results using double:

template <int PRECISION>
double roundP(double f)
{
    const int temp = Pow<10,PRECISION>::result;
    return round(f*temp)/temp;
}

Printed with precision 20:

3

3.1000000000000000888

3.1400000000000001243

3.1419999999999999041

3.1415999999999999481

3.1415899999999998826

3.1415929999999998579

3.1415926999999999047

Community
  • 1
  • 1
Antonio
  • 19,451
  • 13
  • 99
  • 197
3

I will briefly optimize on the last few answers, converting the input number to a double first to prevent overflow. A sample function (not too pretty, but works just fine):

#include <cmath>

// round float to n decimals precision
float round_n (float num, int dec)
{
    double m = (num < 0.0) ? -1.0 : 1.0;   // check if input is negative
    double pwr = pow(10, dec);
    return float(floor((double)num * m * pwr + 0.5) / pwr) * m;
}
alexpanter
  • 1,222
  • 10
  • 25
2

You can round a number to a desired precision with the following function

double round(long double number, int precision) {
  int decimals = std::pow(10, precision);
  return (std::round(number * decimals)) / decimals;
}

Check some examples below...

1)

round(5.252, 0)
returns => 5

2)

round(5.252, 1)
returns => 5.3

3)

round(5.252, 2)
returns => 5.25

4)

round(5.252, 3)
returns => 5.252

This function works even for numbers with 9 precision.

5)

round(5.1234500015, 9)
returns => 5.123450002
Victor
  • 1,904
  • 18
  • 18
1

I once wrote a little function which rounds doubles up to a fixed precision (of 2 decimal cases - like 0.01) while not needing to include <cmath>:

constexpr double simplyRounded( const double value )
{
    return (((((int)(value * 1000.0) % 10) >= 5) + ((int)(value * 100.0))) / 100.0);
}   

...which could be adapted to give you a precision of 1 decimal case (like 0.1), taking and return float, like this:

constexpr float simplyRounded( const float value )
{
    return (((((int)(value * 1000.0f) % 10) >= 5) + ((int)(value * 100.0f))) / 100.0f);
}

Pedro V. G.
  • 353
  • 1
  • 4
  • 13
0

Since Mooing Duck edited my question and removed the code saying questions shouldn't contain answers (understandable), I will write the solution here:

float round(float f,float prec)
{
    return (float) (floor(f*(1.0f/prec) + 0.5)/(1.0f/prec));
}
SteveL
  • 3,331
  • 4
  • 32
  • 57
0

Algorithm for rounding float number:

 double Rounding(double src, int precision) {
         int_64 des;
         double tmp;
         double result;
         tmp = src * pow(10, precision);
         if(tmp < 0) {//negative double
            des = (int_64)(tmp - 0.5);
         }else {
            des = (int_64)(tmp + 0.5);
         }
         result = (double)((double)dst * pow(10, -precision));
         return result;
    }
KidNg
  • 305
  • 4
  • 14