将浮点数舍入到预定义点的常规网格

时间:2012-06-26 13:57:07

标签: c++ rounding

我想将浮点数舍入到给定的精度,例如:

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)。

11 个答案:

答案 0 :(得分:24)

只要您的网格是常规的,只需找到从整数到此网格的转换。那么让我们说你的网格是

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
}

答案 1 :(得分:8)

标准ceil()floor()函数没有精度,我想通过添加自己的精度可以解决这个问题 - 但这可能会引入错误 - 例如。

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

我想你可以测试看看这对你来说是否可靠?

答案 2 :(得分:6)

您可以使用的算法:

  • 获得10-to-the-power(有效位数)(= P10)
  • 将您的双倍值乘以P10
  • 添加:0.5(如果是否定则减去 - 请参阅Ankush Shah的评论)
  • 将此总和的整数部分除以(P10) - 答案将是您的四舍五入的数字

答案 3 :(得分:5)

编辑1:我正在寻找python中numpy的解决方案,并没有意识到OP要求C ++哈哈,哦。好吧。

编辑2:哈哈,看起来我甚至没有解决你原来的问题。看起来你真的想要根据小数舍入(操作独立于给定的数字),而不是精度(操作取决于数字),其他人已经解决了这个问题。

我实际上也在寻找这个但是找不到东西,所以我把numpy数组的实现放在一起。看起来它实现了slashmais所说的逻辑。

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

这里也是一个C ++标量版本,你可以使用Eigen(他们有逻辑索引)做一些类似于上面的事情:(我也把它作为练习更多提升的机会哈哈):

#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

答案 4 :(得分:4)

使用floor()ceil()floor会将浮点数转换为下一个较小的整数,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的增量进行四舍五入。

答案 5 :(得分:2)

通常您在编译时知道所需的精度。因此,使用可用的模板化Pow功能here,您可以执行以下操作:

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

经过测试here

结果还显示了浮点表示的不精确性:)

  

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

答案 6 :(得分:2)

我将简要优化最后几个答案,将输入数字转换为双数,以防止溢出。一个示例函数(不太漂亮,但工作得很好):

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

答案 7 :(得分:0)

由于Mooing Duck编辑了我的问题并删除了代码,说问题不应包含答案(可理解),我将在此处编写解决方案:

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

答案 8 :(得分:0)

舍入浮点数的算法:

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

答案 9 :(得分:0)

您可以使用以下功能将数字舍入到所需的精度

yourmachinename\SQLEXPRESS

检查下面的一些例子......

<强> 1)

.

<强> 2)

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

第3)

round(5.252, 0)
returns => 5

<强> 4)

round(5.252, 1)
returns => 5.3

此功能即使对于精度为9的数字也适用。

<强> 5)

round(5.252, 2)
returns => 5.25

答案 10 :(得分:0)

我曾经写过一个小函数,可以将double舍入到固定精度(2个十进制大小写,例如0.01),而不必包含<cmath>

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

......,可以用来给您精度为小数点后1位的数字(例如0.1),采用并返回float,如下所示:

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