当前位置:网站首页>圆整 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
边栏推荐
猜你喜欢
批量导出Arcgis属性表
gcc ,g++,gdb的安装
Export the articles written in CSDN to PDF format
Explanation of login page
【UDS统一诊断服务】四、诊断典型服务(2)— 数据传输功能单元
clion安装教程
Rust的闭包类型(Fn, FnMut, FnOne的区别)
【UDS统一诊断服务】二、网络层协议(1)— 网络层概述与功能
MySQL groups are sorted by a field, and the first value is taken
Cf1427c the hard work of paparazzi
随机推荐
PM2 deploy nuxt project
对象数组与对象指针
MySQL groups are sorted by a field, and the first value is taken
7-21日错题涉及知识点。
【UDS统一诊断服务】二、网络层协议(1)— 网络层概述与功能
Tabbar implementation of dynamic bottom navigation bar in uniapp, authority management
【UDS统一诊断服务】四、诊断典型服务(2)— 数据传输功能单元
日志
Rust 中的 RefCell
Solution to the trial of ycu Blue Bridge Cup programming competition in 2021
Record the installation and configuration of gestermer on TX2, and then use GST RTSP server
进程间通信-互斥锁
Make your own small program
安装pyshp库
jenkspy包安装
P1586 solution to tetragonal theorem
Arcpy为矢量数据添加字段与循环赋值
serde - rust的序列化方案
Excel打开超大csv格式数据
生成验证码