【问题标题】:Modulus (Float) vs Branch模数(浮点数)与分支
【发布时间】:2019-04-19 20:28:57
【问题描述】:

给定 2 个执行相同操作的表达式 ([-3.14, 3.14] -> [0, 6.28]):

a > 0? a : a + 6.28

fmod(a + 6.28, 6.28)

两者在性能上是否存在普遍差异?

编辑: 假设这样的表达式被多次调用(这样性能是相关的)并且输入a 每次都不同。 (使问题更直接地回答)。

【问题讨论】:

  • 有一个非常简单的答案:测量。编写一个基准测试并尝试一下(确保优化器已打开)。这是知道一件事是否真的比另一件事快的唯一方法。
  • 当然,但我想我正在寻找更多经验法则的答案。如果没有,那很好。但我想知道两者之间是否有普遍的好处。
  • godbolt.org 可以对此有所帮助。查看您的两个解决方案使用 gcc 生成的程序集:godbolt.org/z/vEx4F9
  • 另外,另一种选择,std::clamp 用于 C++。
  • 通常在处理角度时,人们更愿意从 [0, 2π] 映射到 [−π, π] 而不是相反,以受益于接近零的浮点精度增加.将较小的负值映射到较大的值会降低准确性。

标签: c++ c modulus branch-prediction


【解决方案1】:
// Tertiary
t = a > 0? a : a + 6.28
// vs fmod
m = fmod(a + 6.28, 6.28)

两者在性能上是否存在普遍差异?

当然,分析是最好的@NathanOlive,但作为一般指南,请考虑优化潜力。

编译器通常会优化a 类型的整个范围,而不是[-3.14, 3.14]。 t,一个简单的计算,很容易优化。

此外,取决于FLT_EVAL_METHOD,在C 中,m 计算被强制转换为double,当然还有一个函数调用。更多的限制意味着更少的优化可能性。 t 可以使用最佳的 FP 宽度。

推荐 a > 0 ? a : a + 6.28 作为一般首选方法。


给定两个做同样事情的表达式

但是他们在域[-3.14, 3.14]上做同样的事情

大约 1/4 的 double 在 [0...1.0] 范围内。 m 使用 a + 6.28 将失去至少 3 到 所有 位的精度。优势:t.

范围不同:
t 的范围是 [0, 6.28]
m的范围是[0, 6.28),不是[0, 6.28]


考虑更高的目标

很明显,代码正在尝试减少三角函数范围。做好这件事比基本的正弦更难。余弦,切线计算本身。见ARGUMENT REDUCTION FOR HUGE ARGUMENTS: Good to the Last Bit

如果代码以度数而不是弧度开头,请首先考虑以度数为单位的advantages


大图

根据a 的派生方式或tm 的使用方式,甚至可能有更好的性能想法。因此,如果性能确实是一个问题,则需要周围的代码,否则我们会错误地进行微优化。

【讨论】:

    猜你喜欢
    • 2011-11-23
    • 1970-01-01
    • 1970-01-01
    • 2013-08-29
    • 2017-11-16
    • 1970-01-01
    • 2010-09-12
    • 1970-01-01
    • 2016-06-01
    相关资源
    最近更新 更多