1

問題は、このかなり基本的な操作に関する最も堅牢で最速の実装についてです。

ベクトル (X,Y) を指定して、指定された長さ desiredLength の共線ベクトルを計算します。これには少なくとも 2 つの方法があります。

1。(X,Y) の長さを求め、それに応じて再スケーリングします。

double currentLength = sqrt(X*X + Y*Y);
if(currentLength == 0) { /* Aye, Caramba! */ }
double factor = desiredLength / currentLength;
X *= factor;
Y *= factor;

二。(X,Y) の方向を見つけ、その方向に desiredLength のベクトルを形成します。

if(X == 0 && Y == 0) { /* Aye, Caramba! */ }
double angle = atan2(Y, X);
X = desiredLength * cos(angle);
Y = desiredLength * sin(angle);

堅牢なアプリの開発、数値安定性の向上、実行の高速化などには、どの方法が望ましいでしょうか?

4

3 に答える 3

2

実装に依存するため、正解はありません。ただし、合理的な最新の実装では、4 つの基本演算 およびsqrtは最後の 2 進数まで正確です。実装の品質の観点からは、 のすべての関数に同じことが当てはまることを期待できますが、math.h確実ではありません。IEEE 算術 (Windows および主流の Unix プラットフォーム) を備えたマシンでは、4 つの演算がハードウェアに実装さ sqrtますが、三角演算は一般にソフトウェアの実装が必要であり、多くの場合、さらに多くの基本的な演算が必要になります。一部の浮動小数点プロセッサは、少なくとも限定された範囲でそれらを直接サポートしていますが、それでも多くの場合、4 つの基本演算よりも大幅に低速です。

これらはすべて、少なくとも速度に関して (そしておそらく数値の安定性に関しても)、最初の実装を支持するものです。

于 2013-09-23T18:22:15.477 に答える
1

sqrt + 2回の乗算は3回の三角演算よりも安価であるため、少なくともパフォーマンスの面では方法1の方が優れていると思います。2 (軸ごと) ではなく 1 つの近似 (sqrt) が含まれるため、他の面でも優れている (または悪くない) と思います。sqrt 近似も、x と y の両方で「共有」されます。

于 2013-09-23T18:23:24.147 に答える
1

hypot の合理的な実装がアンダーフロー/オーバーフロー状態からあなたを救うことができるという理由hypot(x,y)よりも、 Thu をより適切に使用する必要があります。sqrt(x*x+y*y)

例:hypot(1.0e300,1.0e300)またはhypot(1.0e-300,1.0e-300)

次に、x=1.0e-320、y=0 のような段階的なアンダーフロー (非正規化数) の場合でも、x/hypot(x,y) の評価は安全ですが、desiredLength/hypot(x,y) の評価はオーバーフローする可能性があります。

だから私は書くだろう

double h  = hypot(x,y);
double xd = desiredLength*(x/h);
double yd = desiredLength*(y/h);

x、yの両方がゼロの場合、ゼロ除算の例外と nan の結果が得られるため、ifで処理する必要はありません。

于 2013-09-24T01:47:49.413 に答える