当前位置:网站首页>圆整 round 的一点点小细节
圆整 round 的一点点小细节
2022-04-23 05:48:00 【mightbxg】
圆整就是获得一个浮点数最接近的整数,所谓的“四舍五入”便是指的圆整。C++ 中可以调用 std::round
来实现。看起来很简单的操作是吧,其实里面有一些小细节的。
std::round
不能在编译期间计算
编译期(compile-time)计算和运行期(run-time)计算的概念想必大家都懂,如果一个函数能够在编译期间就计算得到结果(这样的函数叫做常量表达式函数 constexpr funciton),那就能够节省运行期的计算时间。某些情况下必须要求在编译期计算,比如模板参数:
template <int N>
void printN() {
std::cout << N << '\n'; }
int main()
{
constexpr int n = std::round(0.5);
printN<n>();
}
上面这段代码在 MSVC 和 Clang 中是无法编译的,因为 std::round
不能在编译期计算!这听起来难以置信,为什么这么简单的函数却只能在运行期计算呢?
答案是错误处理,当圆整失败(圆整结果超出整数范围)时,std::round
将错误信息存放到全局变量(其实是 thread-local,即在单个线程中可以看作是全局,为了线程安全) math_errhandling
中,以便开发者检验是否出错。
显然这样的错误处理机制是运行期间执行的。与圆整一样,std cmath 中所有的数学函数都用了 math_errhandling
,因此都不能在编译期间计算。
不过需要注意的是,GCC 能够在编译期间计算 std 数学函数,所以上面的代码能够用 GCC 正常编译运行。但 C++ 标准 (c++draft) 明确说了:
An implementation shall not declare any standard library function signature as constexpr except for those where it is explicitly required.
大白话就是:标准库中没说是常量表达式的函数被给我瞎改成常量表达式!所以 GCC 的做法算是自作主张吧。为了程序的兼容性,还是尽量不要利用 GCC 这一特性为好。
圆整计算可能比较慢
如果你非常在意计算速度的话,std::round
可能并不是一个好的选择,原因同样是错误处理。
一方面,错误处理会本身会带来额外的时间消耗(错误判断和错误信息写入全局变量)。另一方面,math_errhandling
这一全局变量的存在导致 std::round
无法进行向量化(编译器会自动地将一些计算向量化加速)。
假如你希望获得极致的计算速度,同时能确保圆整结果不会溢出,可以自己实现一个没有错误处理的圆整:
inline static int myRound(double val)
{
return (int)(val + (val >= 0 ? 0.5 : -0.5));
}
或者利用 SSE 指令,应该更快一些:
inline static int myRound(double val)
{
__m128d t = _mm_set_sd(val);
return _mm_cvtsd_si32(t);
}
(其实上面这两个实现来自 OpenCV 的 cvRound
).
圆整并不一定是“五入”
如果你用 OpenCV,会发现 1.5 和 2.5 通过 cvRound
圆整后都是 2,说好的四舍五入呢?
这是因为,cvRound
优先采用 SSE 实现,而 SSE 中的圆整采用的是 bankers’ rounding 策略(又称 statistician’s rounding、Gaussian rounding),这种策略将 x.5 圆整到最接近的偶数 (round half to even),为的是解决统计学中四舍五入带来的结果偏高问题。
默认情况 (FE_TONEAREST) 下,std::round
是四舍五入圆整,std::rint
是 bankers’ rounding。
版权声明
本文为[mightbxg]所创,转载请带上原文链接,感谢
https://blog.csdn.net/mightbxg/article/details/115355251
边栏推荐
- Database - sorting data
- 7-21日错题涉及知识点。
- Rust 的多线程安全引用 Arc
- Log4j2跨线程打印traceId
- 如何安装jsonpath包
- Record the installation and configuration of gestermer on TX2, and then use GST RTSP server
- Object转Json差异之Gson fastJson jackson 修改字段名
- Export the articles written in CSDN to PDF format
- gst-launch-1.0用法小记
- Dynamic creation and release, assignment and replication of objects
猜你喜欢
随机推荐
C语言循环结构程序
类和对象的初始化(构造函数与析构函数)
GDB debugger installation and use
【UDS统一诊断服务】四、诊断典型服务(2)— 数据传输功能单元
【无标题】
Conversion between JS object and string
C#中?的这种形式
C#【文件操作篇】按行读取txt文本
日志
Explanation of the second I interval of 2020 Niuke summer multi school training camp
Robocode教程5——Enemy类
PM2 deploy nuxt project
利用文件保存数据(c语言)
如何安装jsonpath包
大学概率论与数理统计知识点详细整理
线程和进程的关系和区别是什么
根据SQL语句查询出的结果集,将其封装为json
1007 go running (hdu6808) in the fourth game of 2020 Hangzhou Electric Multi school competition
【UDS统一诊断服务】三、应用层协议(1)
Log4j2跨线程打印traceId