将浮点数舍入为预定义点的常规网格
Round a float to a regular grid of predefined points
我想将浮点数舍入到给定的精度,例如:
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)。
只要你的网格是规则的,只需找到从整数到这个网格的转换。因此,假设您的网格是
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
}
标准ceil()
,floor()
函数没有精度,我想可以通过添加您自己的精度来解决这个问题 - 但这可能会引入错误 - 例如
double ceil(double v, int p)
{
v *= pow(10, p);
v = ceil(v);
v /= pow(10, p);
}
我想你可以测试一下,看看这对你来说是否可靠?
编辑 1:我正在寻找 python 中 numpy 的解决方案,但没有意识到 OP 要求C++哈哈,哦,好吧。
编辑2:哈哈,看起来我什至没有解决你原来的问题。看起来您真的想根据小数(操作与给定数字无关)而不是精度(操作取决于数字)进行四舍五入,其他人已经解决了这个问题。
我实际上也在四处寻找这个,但找不到什么,所以我把 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
这也是一个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
的算法:
- 获得 10 次方(有效位数) (=P10)
- 将您的双精度值乘以 P10
- 添加:0.5(如果为负,则减去 - 请参阅Ankush Shah的评论)
- 将此总和的整数部分除以 (P10) - 答案将是您的四舍五入数
使用 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 的增量。
通常您在编译时知道所需的精度。因此,使用此处提供的模板化 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
使用双精度可以获得更好的结果:
template <int PRECISION>
double roundP(double f)
{
const int temp = Pow<10,PRECISION>::result;
return round(f*temp)/temp;
}
精确打印 20:
3
3.100000000000000888
3.1400000000000001243
3.1419999999999999041
3.141599999999999481
3.141589999999998826
3.1415929999999998579
3.1415926999999999047
我将简要优化最后几个答案,将输入数字转换为双优先以防止溢出。一个示例函数(不太漂亮,但工作正常):
#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;
}
以下函数将数字舍入到所需的精度
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
我曾经写过一个小函数,它将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);
}
由于Mooing Duck编辑了我的问题并删除了问题不应包含答案(可以理解)的代码,我将在这里编写解决方案:
float round(float f,float prec)
{
return (float) (floor(f*(1.0f/prec) + 0.5)/(1.0f/prec));
}
四舍五入浮点数的算法:
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;
}
- 为什么与常规GCC不同,即使有"学究性错误",MinGW-GCC也能容忍丢失的返回类型
- 使用对象文件读取三角形数据网格
- 如何从 Skia 路径几何体中获取网格?
- CGAL:如何创建填充边界曲线的曲面网格?
- 检查 2D 网格的某个元素是否与另一个元素共享对角线、水平线或垂直线
- WinAPI 检查窗口是否具有常规标题栏
- 创建具有两个视口的Qt3D C++场景,其中显示适当的不同网格
- 如何从 3D 曲面网格中删除自相交三角形?
- 在均匀网格中处理碰撞
- 更改高度贴图,使其在 4x4 网格上显示 16 个 hieghtmap
- 用于查找网格中最短路径的算法
- 循环通过网格获取温度,但不知道如何告诉程序停止循环
- 使用 glvertex4i 传递网格面索引时的顶点着色器错误
- 如何使用 sdl2 快速绘制像素网格?
- 如何使用条件计算 3D 网格中从一个点到另一个点的所有路径
- 使用 MFC 的表/网格
- 是否可以制作没有内部分割的cgal 3d多多马因网格?
- 获取网格中心的屏幕位置
- C 库从3D文件格式(例如STL)获得常规网格
- 将浮点数舍入为预定义点的常规网格