44

最近リリースされたDoom 3 BFG のソース コードをブラウズしていると、意味をなさないものに出会いました。Doom 3 は、数学関数をidMathクラスにラップします。一部の関数は から対応する関数に進むだけmath.hですが、再実装されたもの ( idMath::exp16() など) は、対応する関数よりもパフォーマンスが高いと思われますmath.h(おそらく精度が犠牲になります)。

しかし、私を当惑させるのは、彼らがfloat idMath::Sqrt(float x)機能を実装した方法です:

ID_INLINE float idMath::InvSqrt( float x ) {
     return ( x > FLT_SMALLEST_NON_DENORMAL ) ? sqrtf( 1.0f / x ) : INFINITY;
}

ID_INLINE float idMath::Sqrt( float x ) {
     return ( x >= 0.0f ) ? x * InvSqrt( x ) : 0.0f;
}

これは、2 つの不必要な浮動小数点演算を実行しているように見えます: 最初に除算、次に乗算です。

元の Doom 3 のソース コードでもこの方法で平方根関数が実装されていたのは興味深いことですが、逆平方根は高速な逆平方根アルゴリズムを使用しています。

ID_INLINE float idMath::InvSqrt( float x ) {

    dword a = ((union _flint*)(&x))->i;
    union _flint seed;

    assert( initialized );

    double y = x * 0.5f;
    seed.i = (( ( (3*EXP_BIAS-1) - ( (a >> EXP_POS) & 0xFF) ) >> 1)<<EXP_POS) | iSqrt[(a >> (EXP_POS-LOOKUP_BITS)) & LOOKUP_MASK];
    double r = seed.f;
    r = r * ( 1.5f - r * r * y );
    r = r * ( 1.5f - r * r * y );
    return (float) r;
}


ID_INLINE float idMath::Sqrt( float x ) {
    return x * InvSqrt( x );
}

内部的に単に'sを呼び出しSqrt(x)ているx * InvSqrt(x)かのように計算する利点はありますか? ここで、非正規化された浮動小数点数に関する重要な何かが欠けているのでしょうか、それとも id ソフトウェアのずさんな部分ですか?InvSqrt(x)math.hfsqrt(1.f/x)

4

4 に答える 4

8

このようにする理由は2つあります。1つは、「高速invSqrt」法(実際にはニュートンラフソン)が多くのハードウェアで使用されている方法であるため、このアプローチでは、このようなハードウェアを利用できる可能性があります(潜在的に一度に4つ以上のそのような操作を行う)。この記事では、それについて少し説明します。

平方根の計算はどれくらい遅いですか(何サイクル)?

2番目の理由は互換性のためです。平方根を計算するためのコードパスを変更すると、異なる結果(特にゼロ、NaNなど)が得られ、古いシステムに依存していたコードとの互換性が失われる可能性があります。

于 2012-11-28T22:42:16.360 に答える
5

私の知る限り、InvSqrt色は光が表面から跳ね返る角度に依存するという意味で色を計算するために使用されます。これにより、平方根の逆数を使用して関数が得られます。

彼らの場合、これらの数値を計算する際に大きな精度は必要ないため、Doom 3 のコード (元は Quake III から) の背後にいるエンジニアは、数回のニュートン ラフソンの反復のみを使用して近似値を計算する非常に高速な方法を思いつきました。InvSqrt.

InvSqrtこれが、組み込みの(遅い)関数を使用する代わりに、すべてのコードで使用する理由です。x * InvSqrt(x)の使用は、作業が 2 倍になるのを避けるためにあると思います(1 つは 用、もう1 つは 用の2 つの非常に効率的な関数を持つことにより)。InvSqrtSqrt

この記事を読むと、この問題に光が当たるかもしれません。

于 2012-12-04T20:45:03.723 に答える
3

コードが複数の人によって変更された場合、特に改訂履歴がなければ、現在の形式になっている理由についての質問に答えるのが難しくなります。

しかし、プログラミング経験の 3 分の 1 世紀を考えると、このコードは他の人が言及したパターンに適合しますInvSqrt。その後InvSqrt、変更され、誰も更新されませんSqrtでした。

于 2012-12-04T21:09:04.843 に答える
2

sqrtfまた、数値が大きくなると著しく遅くなる、比較的単純なバージョンに出くわした可能性もあります。

于 2012-12-04T20:55:36.370 に答える