Redondea un flotador a una cuadrícula regular de puntos predefinidos

Quiero redondear un número flotante a una precisión dada, por ejemplo:

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 

No puedo explicarlo mejor, pero la razón para esto es traducir una ubicación de punto (como 0.131f, 0.432f) a la ubicación del mosaico en una cuadrícula (como 0.1f, 0.4f).

Mientras su red sea regular, solo encuentre una transformación de enteros a esta grilla. Entonces digamos que su grilla es

 0.2 0.4 0.6 ... 

Luego pasas por

 float round(float f) { return floor(f * 5 + 0.5) / 5; // return std::round(f * 5) / 5; // C++11 } 

Las funciones estándar de ceil() , floor() no tienen una precisión, supongo que podría solucionarlo agregando su propia precisión, pero esto puede introducir errores. Por ejemplo,

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

Supongo que podrías probar para ver si esto es confiable para ti.

Un algoritmo que puedes usar:

  • obtener 10 a la potencia (número de dígitos significativos) (= P10)
  • multiplica tu doble valor por P10
  • agregue: 0.5 (o reste si es negativo – vea el comentario de Ankush Shah)
  • divide la porción entera de esta sum por (P10) – la respuesta será tu número redondeado

EDIT 1: Estaba buscando soluciones para numpy en python y no me di cuenta de que el OP pidió C ++ jaja, bueno.

EDIT 2: Lol, parece que ni siquiera me he dirigido a tu pregunta original. Parece que realmente quieres redondear de acuerdo con un decimal (la operación es independiente del número dado), no una precisión (la operación depende del número), y los otros ya lo han abordado.

En realidad estaba buscando esto pero no pude encontrar algo, así que armé una implementación para matrices numpy. Parece que implementa la lógica que slashmais declaró.

 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 

Aquí también hay una versión escalar de C ++, y probablemente puedas hacer algo similar al anterior usando Eigen (tienen indexación lógica): (También tomé esto como una oportunidad para practicar un poco más de jaja):

 #include  #include  #include  #include  #include  #include  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 vector& operator< <(vector &x, const T &item) { x.push_back(item); return x; } int main() { vector 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 rounder = boost::bind(&pround, _1, 3); vector newList; newList < < 1.2345 << 1034324.23 << 0.0092320985; BOOST_FOREACH(double x, newList) { cout << rounder(x) << "\n"; } return 0; } 

Salida:

 0.1 0 0.6 0.5 0.1 0 1 1 1.23 1.03e+06 0.00923 

Use floor() y ceil() . floor convertirá un flotante al siguiente entero más pequeño, y ceil al siguiente más alto:

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

Creo que lo siguiente funcionaría:

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

floor( f + 0.5 ) redondeará a un número entero. Al multiplicar primero por 10 y luego dividir el resultado por 10, estás redondeando en incrementos de 0.1.

Por lo general, usted conoce la precisión deseada en el momento de la comstackción. Por lo tanto, utilizando la función de Pow con plantilla disponible aquí , puede hacer:

 template  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; } 

Probado aquí .

El resultado también muestra cuán imprecisa es la representación en coma flotante 🙂

3

3.099999905

3.140000105

3.14199996

3.141599894

3.141590118

3.141592979

3.141592741

Puede obtener mejores resultados utilizando el doble:

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

Impreso con precisión 20:

3

3.1000000000000000888

3.1400000000000001243

3.1419999999999999041

3.1415999999999999481

3.1415899999999998826

3.1415929999999998579

3.1415926999999999047

Voy a optimizar brevemente en las últimas respuestas, convirtiendo el número de entrada a una doble para evitar el desbordamiento. Una función de muestra (no muy bonita, pero funciona bien):

 #include  // 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; } 

Como Mooing Duck editó mi pregunta y eliminó el código diciendo que las preguntas no deberían contener respuestas (comprensibles), escribiré la solución aquí:

 float round(float f,float prec) { return (float) (floor(f*(1.0f/prec) + 0.5)/(1.0f/prec)); } 

Algoritmo para redondear el número de flotación:

  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; } 

Puede redondear un número a la precisión deseada con la siguiente función

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

Vea algunos ejemplos a continuación …

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 

Esta función funciona incluso para números con precisión de 9.

5)

 round(5.1234500015, 9) returns => 5.123450002