圆整就是获得一个浮点数最接近的整数,所谓的“四舍五入”便是指的圆整。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,benchmark).

圆整并不一定是“五入”

如果你用 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。

圆整 round 的一点点小细节相关推荐

  1. final的8个小细节,听说只有高手才知道!你知道几个?

    final关键字是一个常用的关键字,可以修饰变量.方法.类,用来表示它修饰的类.方法和变量不可改变,下面就聊一下使用 final 关键字的一些小细节. 细节一.final 修饰类成员变量和实例成员变量 ...

  2. PCB设计中容易忽视的小细节 一分钟帮你总结

    PCB设计是一份严谨.仔细的工作.在PCB设计过程中有非常多的小细节,一些个小细节如果是没有注意好的话,极大可能会影响整个PCB的性能,乃至决定整个产品的成败. PCB布局规范细节 1.在开关电源高压 ...

  3. 装修需要注意的小细节

    快装集成墙面效果视频 这些年,随着人们生活水平的逐渐提高,人们对装修的要求也越来越高,那么对于装修,其中有一些需要注意的小细节,大家有知道多少呢?下面就针对此话题来给大家简单的谈一谈. 1.关于卧室 ...

  4. 如何用C语言改变宏定义的大小,C语言中宏定义使用的小细节

    C语言中宏定义使用的小细节 #pragma#pragma 预处理指令详解 在所有的预处理指令中,#Pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作.#p ...

  5. mysql被拖垮_说几个拖垮系统的小细节!

    本文首发于个人微信公众号<andyqian>,期待你的关注! 前言 有好几天没有更新了,期间确实比较忙些,以至于周末也没休息.在这期间,感触还是蛮深的.现在碎片化的想法等整理好后,再以文章 ...

  6. final关键字的这8个小细节,你get到几个?

    前言 大家好,我是狂聊君. 今天来聊 final 关键字,因为最近在看的几本书都讲到了 final 关键字,发现好多小细节自己都忽视了,抽空总结了一下,分享给大家. 正文 final关键字是一个常用的 ...

  7. 网站优化有什么值得注意的小细节吗?

    网站优化的目的就是让网站关键词达到首页,从而为网站带来更多的流量,促使网站达到更好的营销效果,那么对于关键词上首页有什么技巧,需要完善哪些细节呢?下面就跟大家一起分享一下. 一.挖掘更精准的关键词 对 ...

  8. ASP.NET MVC 自定义路由中几个需要注意的小细节

    本文主要记录在ASP.NET MVC自定义路由时,一个需要注意的参数设置小细节. 举例来说,就是在访问 http://localhost/Home/About/arg1/arg2/arg3 这样的自定 ...

  9. 学长的求职经验 记录【就业创业信息网、求职流程、求职小细节】

    目录 1.就业创业信息网 2.求职流程 3.求职小细节 4.毕业设计 1.就业创业信息网 郑州轻工业大学 就业创业信息网:http://job.zzuli.edu.cn/   郑州大学 就业创业信息网 ...

最新文章

  1. 【工具】git笔记(一)
  2. 概率机器人总结——占用栅格地图先实践再推导
  3. C++中map的使用
  4. 计算机控制系统为什么会受到干扰,浅谈计算机控制系统中的干扰及其抑制措施...
  5. 北大“四大疯人院”之说
  6. c语言程序位置式pid算法,增量式与位置式PID算法(C语言实现与电机控制项目)...
  7. Debian6 搭建GlusterFS集群-Striped Volumes
  8. 支持tls的tcp服务器,TCP+TLS
  9. 【TabularData】DNN和表格数据分析建模综述
  10. C语言程序设计---跟随Frank-FuckPPT
  11. 运维工程师高阶面试总结
  12. Kryo 缓冲区溢出
  13. airtest--自动刷喵币
  14. 红米9A成功root.9秒解锁BL MIUI12 root权限刷 Magisk面具 TWRP
  15. vscode Trace/breakpoint trap 问题
  16. [读论文]弱监督学习的精确 3D 人脸重建:从单个图像到图像集-Accurate 3D Face Reconstruction with Weakly-Supervised Learning:From
  17. Design Compiler知识点汇总
  18. Activiti7.0 EL NullPoint问题
  19. 国培南通之行的感悟——(其二)
  20. 修复win+v无法弹出剪贴板的问题

热门文章

  1. ComSec作业7:Signature
  2. 【医学图像处理】 2 灰度直方图、图像二值化(阈值分割)
  3. JVM 新生代老年代与GC
  4. math@间断点@连续@可导@可微@微积分基本定理
  5. 华为ENSP中AP与AC的配置
  6. CSS(二):常用CSS样式[文字、文本、背景......]
  7. 人人车Android客户端架构演进实录
  8. 教师网络计算机研修培训总结,教师远程培训研修总结范文(精选6篇)
  9. 图片太多怎么办?快速教会你批量重命名图片名称,还桌面整洁
  10. Maemo Linux手机平台系列分析:6 Maemo平台开发之D-Bus