【问题标题】:How much does it save to check before calling sqrt when normalizing a 3d vector在规范化 3d 矢量时调用 sqrt 之前检查可以节省多少
【发布时间】:2019-07-16 22:02:03
【问题描述】:

AFAIK 在大多数情况下,sqrt 操作都很昂贵。 下面对向量的测试是否已经是长度为 1 且具有 epsilon 的值?是不是省了很多。如果 normalize 经常在已经标准化的向量上调用。如果不是,是不是太贵了?

double Vec3d::normalize() {
    double  mod = x * x + y * y + z * z;
    if (mod == 0) {
        return(0);
    }
    if (consideredEqual(mod, 1.0, .0000001)) {  // is this test worth it ???
        return(1.0);
    }
    mod = std::sqrt(mod);
    x /= mod;
    y /= mod;
    z /= mod;
    return mod;
}

【问题讨论】:

  • 无论何时在这里询问性能 - 自己首先测试代码。
  • 这取决于您的输入的统计分布。你希望我们怎么知道?
  • 由于缓存命中等原因,在这种环境中相当困难。我认为很多人在通用平台上都这样做了,因为所有 3D 图形都需要这个,所以很多人会立即得到是/否的答案。否则我必须编写一个特殊的测试程序等。一旦发布答案,希望其他有相同问题的人可以轻松找到它(我没有)
  • 对我来说是典型的带有数学协处理器和标准 C++ 库的英特尔 64 位 PC。
  • 最好的了解方法是编写基准测试。坦率地说,这可能比写一个问题并等待回复要快。

标签: c++ math geometry


【解决方案1】:

对于最近的奔腾微架构,sqrt 的延迟为 10-22 个周期(相比之下,fp add 为 3cy,fp mult 为 5cy,类型转换 fp-int 为 2-4cy) .成本要高得多,尤其是sqrt 不是流水线,它只能每 5 个周期启动一个新操作。

但添加测试可能不是一个好主意,因为测试也有必须考虑的成本。在具有深流水线的现代处理器中,会提前获取指令以填充流水线,并且分支可能需要忘记所有这些获取的指令。为了限制这种讨厌的影响,处理器尝试“预测”测试的行为:是否采用分支以及目标地址是什么?预测是基于程序行为的规律性。当前的预测器非常好,并且对于许多问题,如果正确预测,分支不会有很大的成本。 但是预测可能会失败,并且错误预测会花费 15-20 个周期,这是非常高的。

现在尝试粗略地评估一下您提出的修改的好处。我们可以考虑几种情况。

  1. 90% 的时间值是 != 1.0 和 10% 的时间等于 1.0。基于这种行为,分支预测器会打赌你不会选择分支(值!=1.0)。
    所以 90% 的时间你有一个正常的 sqrt 来计算(并且测试成本可以忽略不计)和 10% 的时间,你有一个错误的预测。您避免了 10-20 个周期的 sqrt,但您支付了 15 个周期的分支罚款。增益为零。

  2. 90% 的时间值 = 1.0 和 10% 的时间值不同。分支预测器会假设您选择了分支。
    当值为 1.0 时,您有明显的胜利并且成本几乎为零。 10% 的时间你会支付一个分支错误预测和一个 sqrt。与 100% sqrt 相比,平均而言,有一个胜利。

  3. 50% 的值为 1.0 和 50% 不同。这在某种程度上是一个灾难场景。分支预测器很难找到明确的分支行为,并且可能在很大一部分时间里失败,如果你很不幸的话,可能会失败 40% 到 100%。您将在计算成本中添加许多分支错误预测,并且您可能会获得负收益!!!

这些估计非常粗略,需要对您的数据模型进行更精细的计算,但可能除非您的大部分数据是 1.0,否则您最多不会获得任何收益,甚至可能会放缓。

您可以在 Agner Fog https://www.agner.org/optimize 的网站上找到运营成本的衡量标准

【讨论】:

  • 谢谢 - 我正在寻找的“直觉水平”答案。当然,运行真正的测试意味着需要知道依赖于应用程序的数据分布,并且应用程序尚未构建。我在通过一堆变换运行光线并且在每次变换时都需要方向的标准化版本时正在考虑它。如果每个所有转换都被缩放,似乎 sqrt 将是该操作花费的大约 20%。这是具有大量实际 3D 图形经验的人在许多情况下的测试中都会遇到的问题。
【解决方案2】:

对以下问题的回答表明,将其用于标准 C 库和编译器以及具有 fpus 的当前处理器的一般用途是不值得的。但在已知的有限情况下或在没有浮点支持的处理器上,这可能是微不足道的。

c++ practical computational complexity of <cmath> SQRT()

【讨论】:

    猜你喜欢
    • 2020-06-05
    • 2013-04-23
    • 1970-01-01
    • 2021-11-04
    • 2011-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多