Round a Float to a Regular Grid of Predefined Points

Round a float to a regular grid of predefined points

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
}

round float values to interval limits / grid

If intervals is sorted, you can use np.searchsorted:

np.array(intervals)[np.searchsorted(intervals, sample)]
# array([ 30., 18., 18., 15., 30., 10., inf, 18., 25., 21.])

searchsorted returns the index of the interval where the element belongs to:

np.searchsorted(intervals, sample)
# array([7, 4, 4, 3, 7, 1, 8, 4, 6, 5])

The default side='left' returns the smallest index of such interval and the result falls into the left open, right close scenario.

Round double to 3 points decimal

A common trick is to do it with maths:

value = round( value * 1000.0 ) / 1000.0;

Where round will handle negative and positive values correctly... Something like this (untested):

inline double round( double val )
{
if( val < 0 ) return ceil(val - 0.5);
return floor(val + 0.5);
}

You'll still want to set the decimal places to 3 during output, due to floating point precision problems.

Python rounding of random floats to nearest points on a 2D uniform mesh grid

In another SO question I helped the questioner use a scipy nearest neigbhor interpolator.

Repeating Scipy's griddata

Working from that I figured out a solution to your problem. In scipy.interpolate I find a NearestNDInterpolator. From that I find that scipy.spatial has a method for finding nearest neighbors:

In [936]: from scipy import interpolate
In [937]: interpolate.NearestNDInterpolator?
...
Docstring:
NearestNDInterpolator(points, values)

Nearest-neighbour interpolation in N dimensions.
...
Uses ``scipy.spatial.cKDTree``

In [938]: from scipy import spatial
In [939]: spatial.cKDTree?

cKDTree is used in 2 steps; create a tree from the grid, and query the nearest neighbors.

From your meshgrid I can create a (n,2) array of points

In [940]: xx, yy = np.meshgrid(x, y)
In [941]: xygrid=np.array([xx,yy])
In [942]: xygrid=xygrid.reshape(2,-1).T # clumsy

create a search tree:

In [943]: tree=spatial.cKDTree(xygrid)

test set of points, (10,2):

In [944]: a=np.random.multivariate_normal([0,0], [[l/2,0],[0,l/2]],10)

Query of the search tree gives 2 arrays, one of distances from nearest neighbor, and one with the indexes:

In [945]: I=tree.query(a)

In [946]: I
Out[946]:
(array([ 0.70739099, 0.9894934 , 0.44489157, 0.3930144 , 0.273121 ,
0.3537348 , 0.32661876, 0.55540787, 0.58433421, 0.538722 ]),
array([61, 72, 85, 72, 82, 39, 38, 62, 25, 59]))

Comparing the a points, with the xygrid nearest neighbor grid points, shows that they indeed appear to be close. A scatter point plot would be better.

In [947]: a
Out[947]:
array([[ 1.44861113, -0.69100176],
[ 1.00827575, 0.80693026],
[ 4.37200745, 3.07854676],
[ 1.2193471 , 1.50220587],
[ 0.12668563, 2.95803754],
[ 1.4758331 , -3.53122635],
[ 0.28425494, -3.03913067],
[ 2.8203361 , 0.40538034],
[-3.67726571, -4.46285921],
[-1.07228578, -0.10834709]])

In [948]: xygrid[I[1],:]
Out[948]:
array([[ 1.6, 0. ],
[ 1.6, 1.6],
[ 4.8, 3.2],
[ 1.6, 1.6],
[ 0. , 3.2],
[ 1.6, -3.2],
[ 0. , -3.2],
[ 3.2, 0. ],
[-3.2, -4.8],
[-1.6, 0. ]])

A solution in rth's link also uses cKDTree. I'm just filling in the details on how to work from your griddata.
Finding index of nearest point in numpy arrays of x and y coordinates

Math round function with variable number of digits

simple arithmetic,

#include <stdio.h>
#include <cmath>

float my_round( float arg, int digits )
{
float retValue = arg * pow(10.0f,(float)digits);
retValue = round(retValue);
return retValue * std::pow(10.0f,(float)-digits);
}

int main()
{
float value = 12.3456789f;
for(int i=-1;i<6;i++)
{
printf("%f\n", my_round(value, i));
}
}

should do the trick, (compiled with g++)

output is :

10.000000
12.000000
12.300000
12.349999
12.346001
12.345699
12.345679

Errors in Casting Doubles to Integers

It is important to understand that not all rational numbers are representable in finite precision. Also, it is important to understand that set of numbers which are representable in finite precision in decimal base, is different from the set of numbers that are representable in finite precision in binary base. Finally, it is important to understand that your CPU probably represents floating point numbers in binary.

2029.00012 in particular happens to be a number that is not representable in a double precision IEEE 754 floating point (and it indeed is a double precision literal; you may have intended to use long double instead). It so happens that the closest number that is representable is 2029.000119999999924402800388634204864501953125. So, you're counting the significant digits of that number, not the digits of the literal that you used.

If the intention of 0.00001 was to stop counting digits when the number is close to a whole number, it is not sufficient to check whether the value is less than the threshold, but also whether it is greater than 1 - threshold, as the representation error can go either way:

 if(test <= 0.00001 || test >= 1 - 0.00001)

After all, you can multiple 0.99999999999999999999999999 with 10 many times until the result becomes close to zero, even though that number is very close to a whole number.

how to round a double to n decimals?

C++11 has std::round in <cmath>.

Without that you can use std::floor and std::ceil on adjusted numbers. E.g. std::floor(n * 100 + 0.5)/100 to round to two decimal places.

Although it should be noted that rounding isn't entirely trivial; There are complications such as choosing to round toward zero, toward negative infinity, round to even, etc. If you're writing programs for production be sure you understand the rounding requirements for your domain.

Round a floating point number to n digits ignoring leading zeros and preserving them

Edit: for an unknown number of 0's I don't see a better alternative than

import re
some_float = 11.00001203456789
how_many_to_keep = 4
regex = r"0[1-9]"
float_part = str(some_float).split(".")[1]
float_limiter = re.search(regex,float_part).start() if float_part.startswith("0") else -1
print(f'{some_float:2.{float_limiter+1+how_many_to_keep}f}')

Which is evaluating the number of 0 in real time using the expression float_limiter+1+how_many_to_keep, and use as a the format parameter. this has gotten a bit ugly but now returns the correct answer on all cases. The output is

11.00001235

comparison float rounding fails System.Math.RoundTo C++ XE7

Your desired precision of 6 decimal digits is very near the precision limits for a float data type. The epsilon, or delta between consecutive representable floating point values, for a number around 40f is about 7.63E-6, so there's only a couple of bits different between the 'best' value and what you're getting. This is possibly due to rounding that close to the limit, but I'm not sure.



Related Topics



Leave a reply



Submit