Je veux arrondir un nombre flottant à une précision donnée, par exemple:
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
Je ne peux pas l'expliquer mieux, mais la raison en est de traduire un emplacement de point (comme 0.131f, 0.432f) en un carreau dans une grille (comme 0.1f, 0.4f).
Tant que votre grille est régulière, il vous suffit de trouver une transformation d’entiers en cette grille. Alors disons que votre grille est
0.2 0.4 0.6 ...
Puis vous tournez par
float round(float f)
{
return floor(f * 5 + 0.5) / 5;
// return std::round(f * 5) / 5; // C++11
}
Les fonctions standard ceil()
, floor()
n'ont pas de précision. Vous pouvez contourner ce problème en ajoutant votre propre précision - mais cela peut introduire des erreurs - par exemple.
double ceil(double v, int p)
{
v *= pow(10, p);
v = ceil(v);
v /= pow(10, p);
}
Je suppose que vous pourriez tester pour voir si cela est fiable pour vous?
Un algorithme que vous pouvez utiliser:
EDIT 1: Je cherchais des solutions pour numpy en python et je ne savais pas que le PO demandait C++ haha, eh bien.
EDIT 2: Lol, on dirait que je n'ai même pas répondu à votre question initiale. Il semble que vous vouliez vraiment arrondir selon une décimale (l'opération est indépendante du nombre donné), pas une précision (l'opération dépend du nombre), les autres ont déjà répondu à cette question.
En fait, je cherchais également cela, mais je ne trouvais rien, alors j’ai assemblé une implémentation pour les tableaux numpy. On dirait qu'il met en œuvre la logique que slashmais a énoncée.
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
Voici une version scalaire C++ également, et vous pourriez probablement faire quelque chose de similaire à ci-dessus en utilisant Eigen (ils ont une indexation logique):
#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;
}
Sortie:
0.1
0
0.6
0.5
0.1
0
1
1
1.23
1.03e+06
0.00923
Utilisez floor()
et ceil()
. floor
convertira un float en entier plus petit, et ceil
en supérieur:
floor( 4.5 ); // returns 4.0
ceil( 4.5 ); // returns 5.0
Je pense que ce qui suit fonctionnerait:
float round( float f )
{
return floor((f * 10 ) + 0.5) / 10;
}
floor( f + 0.5 )
arrondira à un entier. En multipliant d'abord par 10 puis en divisant le résultat par 10, vous arrondissez par incréments de 0,1.
Habituellement, vous connaissez la précision souhaitée au moment de la compilation. Par conséquent, en utilisant la fonction Pow basée sur un modèle disponible ici , vous pouvez faire:
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;
}
Testé ici .
Le résultat montre également combien la représentation en virgule flottante est imprécise :)
3
3.099999905
3.140000105
3.14199996
3.141599894
3.141590118
3.141592979
3.141592741
Vous pouvez avoir de meilleurs résultats en utilisant double:
template <int PRECISION>
double roundP(double f)
{
const int temp = Pow<10,PRECISION>::result;
return round(f*temp)/temp;
}
Imprimé avec précision 20:
3
3.1000000000000000888
3.1400000000000001243
3.1419999999999999041
3.14159999999999994848
3.1415899999999998826
3.1415929999999998579
3.1415926999999999047
Je vais brièvement optimiser les dernières réponses en convertissant le nombre entré en un double premier pour éviter tout débordement. Un exemple de fonction (pas trop jolie, mais fonctionne très bien):
#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;
}
Comme Mooing Duck a modifié ma question et supprimé le code en disant que les questions ne devraient pas contenir de réponses (compréhensibles), je vais écrire la solution ici:
float round(float f,float prec)
{
return (float) (floor(f*(1.0f/prec) + 0.5)/(1.0f/prec));
}
Algorithme pour arrondir le nombre flottant:
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;
}
Vous pouvez arrondir un nombre à la précision souhaitée avec la fonction suivante
double round(long double number, int precision) {
int decimals = std::pow(10, precision);
return (std::round(number * decimals)) / decimals;
}
Vérifiez quelques exemples ci-dessous ...
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
Cette fonction fonctionne même pour les nombres avec une précision de 9.
5)
round(5.1234500015, 9)
returns => 5.123450002