在规范化 3d 向量时,在调用 sqrt 之前检查可以节省多少

How much does it save to check before calling sqrt when normalizing a 3d vector

本文关键字:检查 多少 节省 sqrt 3d 规范化 向量 调用      更新时间:2023-10-16

>AFAIK 在大多数情况下,sqrt 操作的成本很高。 下面的测试对 epsilon 的向量长度已经是 1 值得吗?它节省了很多。如果规范化经常在已经规范化的向量上调用。如果不是,是不是太贵了?

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;
}

对于最近的奔腾微体系结构,sqrt的延迟为 10-22 个周期(相比之下,FPadd为 3cy,FPmult为 5cy,类型转换为 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 的站点中找到运营成本的度量

对以下问题的回答表明,对于标准 C 库和编译器以及带有 fpu 的当前处理器的一般使用来说,这是不值得的。 但是,在已知的有限情况下或在没有浮动支持的处理器上,它可能不值得。

SQRT() 的 C++ 实际计算复杂度