Округлить поплавок до регулярной сетки заданных точек
Я хочу округлить число с плавающей точкой с заданной точностью, например:
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
Я не могу объяснить это лучше, но причина этого заключается в том, чтобы перевести точечное местоположение (например, 0,131f, 0,432f) в местоположение плитки в сетке (например, 0,1f, 0,4f).
Ответы
Ответ 1
Пока ваша сетка является регулярной, просто найдите преобразование из целых чисел в эту сетку. Итак, пусть ваша сетка
0.2 0.4 0.6 ...
Затем вы раунд
float round(float f)
{
return floor(f * 5 + 0.5) / 5;
// return std::round(f * 5) / 5; // C++11
}
Ответ 2
Стандартные функции ceil()
, floor()
не имеют точности, я думаю, можно обойти это, добавив вашу собственную точность - но это может привести к ошибкам - например,
double ceil(double v, int p)
{
v *= pow(10, p);
v = ceil(v);
v /= pow(10, p);
}
Думаю, вы могли бы проверить, действительно ли это для вас?
Ответ 3
Алгоритм, который вы можете использовать:
- получить 10-к-силе (число значащих цифр) (= P10)
- умножьте двойное значение на P10
- add: 0.5 (или вычесть, если отрицательный - см. комментарий Ankush Shah)
- разделите целочисленную часть этой суммы на (P10) - ответ будет вашим округленным числом
Ответ 4
EDIT 1: Я искал решения для numpy в python и не понимал, что OP попросил С++ haha, ну хорошо.
EDIT 2: Lol, похоже, я даже не обратился к вашему оригинальному вопросу. Похоже, вы действительно хотите округлить в соответствии с десятичной (операция не зависит от заданного числа), а не точность (операция зависит от числа), а другие уже обратились к этому.
Я тоже искал это, но не смог найти что-то, поэтому я собрал реализацию для массивов numpy. Похоже, что он реализует логику, о которой говорил слшмаи.
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
Здесь также скалярная версия С++, и вы, вероятно, могли бы сделать что-то подобное выше, используя Eigen (у них есть логическое индексирование): (Я также воспринял это как возможность попрактиковаться в еще одном повышении 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;
}
Вывод:
0.1
0
0.6
0.5
0.1
0
1
1
1.23
1.03e+06
0.00923
Ответ 5
Используйте floor()
и ceil()
. floor
преобразует float в следующее меньшее целое число и ceil
к следующему выше:
floor( 4.5 ); // returns 4.0
ceil( 4.5 ); // returns 5.0
Я думаю, что следующее будет работать:
float round( float f )
{
return floor((f * 10 ) + 0.5) / 10;
}
floor( f + 0.5 )
округляется до целого числа. Первым умножением на 10 и последующим делением результата на 10 вы округляете с шагом 0,1.
Ответ 6
Обычно вы знаете требуемую точность во время компиляции. Поэтому, используя функцию Templated Pow, доступную здесь, вы можете сделать:
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;
}
Протестировано здесь.
Результат также показывает, насколько неточным является представление с плавающей запятой:)
3
3,099999905
3,140000105
3.14199996
3,141599894
3,141590118
3,141592979
3,141592741
У вас могут быть лучшие результаты с использованием double:
template <int PRECISION>
double roundP(double f)
{
const int temp = Pow<10,PRECISION>::result;
return round(f*temp)/temp;
}
Отпечатано с точностью 20:
3
+3,1000000000000000888
+3,1400000000000001243
+3,1419999999999999041
+3,1415999999999999481
+3,1415899999999998826
+3,1415929999999998579
+3,1415926999999999047
Ответ 7
Я кратко оптимизирую последние несколько ответов, сначала преобразуя число ввода в двойное, чтобы предотвратить переполнение. Примерная функция (не слишком красивая, но отлично работает):
#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;
}
Ответ 8
Так как Mooing Duck отредактировал мой вопрос и удалил код, говорящий, что вопросы не должны содержать ответы (понятно), я напишу решение здесь:
float round(float f,float prec)
{
return (float) (floor(f*(1.0f/prec) + 0.5)/(1.0f/prec));
}
Ответ 9
Алгоритм для округления числа с плавающей запятой:
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;
}
Ответ 10
Вы можете округлить число с желаемой точностью с помощью следующей функции
double round(long double number, int precision) {
int decimals = std::pow(10, precision);
return (std::round(number * decimals)) / decimals;
}
Проверьте некоторые примеры ниже...
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
Эта функция работает даже для чисел с точностью до 9.
5)
round(5.1234500015, 9)
returns => 5.123450002
Ответ 11
ответ, который вы ищете
введите описание ссылки здесь