2012-04-13 5 views
12

私は、多くの場合、斜辺を計算伴うJavaScriptでシミュレーションとアニメーションについての質問の数を見てきました:JavaScriptの中で最も速い斜交ですか?

hypot = Math.sqrt(x*x + y*y); 

デカルト座標は、これらのエンジンのほとんどに選択の武器なので、これらの計算をするために必要とされます対の点の距離などを見つけることができます。斜辺を計算する際のスピードアップは、多くのプロジェクトにとって大きな助けになります。

この目的のために、上記の単純な実装よりも速い方法がありますか?私はクロムで少し速かった近似を見つけましたが、this approximation function in SuperColliderに基づいて、Firefoxではずっと遅くなっていました。

編集2015-08-15:私は受け入れられた答えをMath.hypotのものに切り替えました。私は現時点での実用的なアプローチは、Math.hypotまたは合成されたhypot関数を利用できない場合はそれを使用し、十分で、Math.hypotが利用できない場合は、schの答えに対して四角形と比較することだと考えています。

+3

あなたはいつもそれがピタゴラス式を使用するすべてのスクリプトをスピードアップしたいあなたの高貴だ[一部0x5f3759dfマジック](http://en.wikipedia.org/wiki/Fast_inverse_square_root) – violet313

+1

を使用することができます。しかし、私は式をより速くするための一般的な解決策はないと考えています(それ以外の場合、2,500歳のバージョンは使用しません)。式を高速化しようとするのではなく、コードをリファクタリングして、式をlessにし、式がコードのパフォーマンスのボトルネックであることを実証した後でのみ実行してください。 – Kevin

+0

@Kevin:Cやその他のオーバーヘッドの少ない言語では、実際には高速化する近似があります。近似が有用かどうかは、モデルが必要とする精度に依存しますが、ゲーム物理学では、ゲームプレイをより流動的にすると一般に価値があります。 –

答えて

1

ECMAScriptのES6で使用できるMath.hypot

// ES5 support 
 

 
Math.hypot = Math.hypot || function(x, y){ return Math.sqrt(x*x + y*y) } 
 

 
var x = 3, y = 4; 
 

 
document.write(Math.hypot(x, y))

編集:あなたは、空白のタブでこのテストを実行し、両方と200万操作していることができますメソッドは、結果は非常に良いです、それは24%高速です。

var i, tmp, x = 55, y = 66, end, ini = performance.now(); 

// Math.sqrt operation 
i = 0; 
ini = performance.now(); 
tmp = 0; 
while(i++ < 2000000){ 
    tmp += Math.sqrt(x*x + y*y) 
} 
end = performance.now(); 
console.log(tmp, "Math.sqrt operation: " + (end - ini) + " ms"); 

// Math.hypot 

i = 0; 
ini = performance.now(); 
tmp = 0; 
while(i++ < 2000000){ 
    tmp += Math.hypot(x, y) 
} 
end = performance.now(); 

console.log(tmp, "Math.hypot: " + (end - ini) + " ms"); 

:このテストでは、それはES6のMath.hypotを使用しています。

enter image description here

+0

Ooh、そのパフォーマンスに関する考えは? –

+0

@PhilH Edit、私はMath.sqrtとMath.hypotで操作をテストしました。あなたはそれを見ることができます。このテストでは、Math.hypotの元の関数が使用されています。 –

+0

Chrome 62では、「hypot」が一貫して遅く表示されます。私は、外部の干渉を最小限に抑えるために厳密な関数に入れようとしました(https://gist.github.com/anonymous/159187ac9a8d3caf97737cd9cf551c1a )、sqrtはより高速な操作のままです。おそらく、彼らはある時点でオーバーフロー/アンダーフローに対して何らかの保護を追加しましたか? – Arthur2e5

13

多くの場合、平方根を計算する必要はなく、hypot^2 = x*x + y*yで十分です。これは、たとえば、距離を比較し、実際の値を必要としない場合に当てはまります。

0

xyの等価を見ることができます。等しい場合は、斜辺を(x + y)/sqrt(2)として計算できます。ここで、sqrt(2)は定数です。

この方法は、x = yの場合に使用できます。それ以外の場合には最大41%の不正確さで使用することができます。これは大きな誤りです。しかし、許容誤差限界を指定するときは、この方法を使用できます。たとえば、許容誤差を5%に定義すると、b0.515*a1.942*aの間になければなりません。

計算の完全な不正確さを必要としない場合は、値の範囲での計算のパフォーマンスを向上させることができます。

類推によって、xまたはyからzeroの等価を見ることができます。そして、いくつかの正確さで、この場合にはより高速に斜辺を計算します。

P.S.私はこれについて1つのrussian articleで読んだ。多くの人が知らない

6

重要なポイント:理論的には動作しますが、実際には、それは失敗することがあり

hypot = Math.sqrt(x*x + y*y);

。 xがxのxより大きいとx * xがオーバーフローするので、コードは無限の結果を生成します。

オーバーフローを起こさずにsqrt(x x + y)を計算する方法は次のとおりです。

max = maximum(|x|, |y|) 
min = minimum(|x|, |y|) 
r = min/max 
return max*sqrt(1 + r*r) 

リファレンスと完全なテキスト:ジョン・D.クック - http://www.johndcook.com/blog/2010/06/02/whats-so-hard-about-finding-a-hypotenuse/

+0

(プラス1)計算のオーバーフローなどの実装上の問題について言及することは良いことです。 –

+0

に1つの詳細を加え、少なくとも1つの 'x'と' y 'はゼロではない、そうでなければresultyは '無限大' –

関連する問題