5倍の減速を引き起こすブール評価の真実性を否定しますか?
-
03-10-2019 - |
質問
私はオクトリーを実装しようとしています。そのために、高速AABB線交差点アルゴリズムが必要です。いくつかの検索の後、私は出会いました これ それを提供しているように思われた紙。ソースコードから、利用可能 ここ, 、翻訳しました pluecker_cls_cff
これとしてc#への関数:
public bool Intersect_2(ref RayPluecker r)
{
switch (r.Classification)
{
// 7 same-ish cases snipped
case Classification.PPP:
return !((r.Position.X > this.Max.X) || (r.Position.Y > this.Max.Y) || (r.Position.Z > this.Max.Z) ||
(r.PlueckerCoefficient.X + r.Direction.X * this.Max.Y - r.Direction.Y * this.Min.X < 0) ||
(r.PlueckerCoefficient.X + r.Direction.X * this.Min.Y - r.Direction.Y * this.Max.X > 0) ||
(r.PlueckerCoefficient.Y + r.Direction.X * this.Min.Z - r.Direction.Z * this.Max.X > 0) ||
(r.PlueckerCoefficient.Y + r.Direction.X * this.Max.Z - r.Direction.Z * this.Min.X < 0) ||
(r.PlueckerCoefficient.Z - r.Direction.Z * this.Min.Y + r.Direction.Y * this.Max.Z < 0) ||
(r.PlueckerCoefficient.Z - r.Direction.Z * this.Max.Y + r.Direction.Y * this.Min.Z > 0));
}
return false;
}
これは正常に動作しているようですが、私にとってはかなり遅いように見えました(1000万の交差を行うには250ms)ので、さまざまな品種でマイクロベンチマークを試しました。 1つでは、直後にある否定を削除しました return
ステートメントとすべての比較を逆転させた(>
に <
およびVisa Versa)。
雪が降る:
case Classification.PPP:
return ((r.Position.X < this.Max.X) || (r.Position.Y < this.Max.Y) || (r.Position.Z < this.Max.Z) ||
(r.PlueckerCoefficient.X + r.Direction.X * this.Max.Y - r.Direction.Y * this.Min.X > 0) ||
(r.PlueckerCoefficient.X + r.Direction.X * this.Min.Y - r.Direction.Y * this.Max.X < 0) ||
(r.PlueckerCoefficient.Y + r.Direction.X * this.Min.Z - r.Direction.Z * this.Max.X < 0) ||
(r.PlueckerCoefficient.Y + r.Direction.X * this.Max.Z - r.Direction.Z * this.Min.X > 0) ||
(r.PlueckerCoefficient.Z - r.Direction.Z * this.Min.Y + r.Direction.Y * this.Max.Z > 0) ||
(r.PlueckerCoefficient.Z - r.Direction.Z * this.Max.Y + r.Direction.Y * this.Min.Z < 0));
これは同じ結果をもたらすはずですよね?いくつかのテストケースで否定されたバージョンと同じ結果を返すため、そう思われました。ただし、ベンチマークでは、5倍高速でした(1,000万の交差を行うには50ms)!私はそれが最適化されていなかったと確信しています、私のベンチマークは次のように見えます:
for (int i = 0; i < 10000000; i++)
{
if (!box.Intersect_3(ref ray))
{
throw new Exception();
}
}
この大きな違いを説明できるものは何ですか? x86で.net 4.0を実行しています。
解決
2番目のコードは、最初のコードと同じことをしません。
すでに行った変更に加えて、すべてのORをAndsに変える必要があります。 (見る デ・モーガンの法律.)
修正を行った後、2つのバージョンが同じ速度で実行されることは間違いありません。
他のヒント
パフォーマンスに特に関連して、2番目のケースよりも早くリターンステートメントが短絡するのは、最初のケースよりも短絡です。比較の順序を変更しようとする価値があるかもしれません。 ||の代わりに&&を使用して計算を同等に変更する場合2番目のケースでは、虚偽のものが最初に来る可能性が最も高いものが必要です。