距離ではなく、距離の二乗チェックを使用することの欠点はありますか?


29

私は基本的にすべての距離(vector3の長さ)のチェックに距離の2乗チェックを使用します。これは、平方根が発生しないことによるパフォーマンスの向上(プレーン長のチェックなど)によるものです。

それの外観から、二乗距離チェックはあらゆる状況でうまく機能します:

if x^2 < y^2, then x < y, even when 0 < (x or y) < 1

距離と距離の2乗は常に正になるため、xまたはyが0より小さい状況は考慮していません。

これが機能するので、距離チェックは決して必要ではないように見えますが、何かが欠けているというしつこい感じがします。これは、精度が重要な状況でも維持されますか?

回答:


41

長さの2乗を使用して距離を比較する場合、私が気づいている不利な点はありません。そのように考えてください:あなたはそれをスキップしているだけで、sqrtそれ以上の正確さは得られません。実際のユークリッド距離が必要ない場合は、安全に残すことができますsqrt除外。

もちろん、長さの2乗はユークリッド距離とは大きく異なるため、パスファインディングヒューリスティックのようなものには適していません。


16
平方根は実際に距離チェックから精度を削除します。1から2までの固定小数点数の平方根を取得し、結果(1からsqrt(2)まで)をまったく同じ範囲で保存しようとする試みと考えることができます。x ^ 2 <y ^ 2として比較されるいくつかの距離は、平方根を取得した後にx = yとして比較されます。長さの二乗チェックは、より高速で正確です。
ジョンカルスビーク

bummzackとJohn Calsbeekのすばらしい回答をありがとう!あなたの回答が組み合わさって私の質問に完全に答えます。平方根を使用しないことによる追加のメモリ空間は考慮しませんでした。そして、そのヒューリスティックリンクは素晴らしい読み物になります
-Aralox

1
A *の場合を除きます。さまざまなヒューリスティックのテスト済みでd^2恐ろしいパフォーマンスを説明した記事を読んだことを思い出します。A *では|dx| + |dy|うまく機能します。1か月ほど前に読んだときにリンクがありません。
ジョナサンディキンソン

3
A *の場合、距離を単に比較するのではなく、距離を追加するため、sqrtをスキップしても違いが生じます。
amitp

1
@bobobobo同意します。私はほとんどの場合、他の方向、つまり通常の距離がどういうわけかより正確であるという潜在的な議論を撃ち落とすようにしました。
ジョンカルスビーク

14

bummzackがPath-findingの類推でほのめかしたように、距離を足し合わせてその合計を比較するたびに「通常の」長さを使用する必要があります。(長さの二乗和が長さの二乗和と異なるためです)。

x ^ 2 + y ^ 2!=(x + y)^ 2


4

私が考えることができる唯一の欠点は、二乗するとオーバーフローする大きな数を扱うときです。

たとえば、Javaの場合:

int x = Integer.MAX_VALUE / 1000000; //2147
int y = Integer.MAX_VALUE / 5000; //429496
System.out.println("x < y: " + (x < y)); //true
System.out.println("x*x: " + (x * x)); //4609609
System.out.println("y*y: " + (y * y)); //-216779712 - overflows!
System.out.println("x*x < y*y: " + (x * x < y * y)); //false - incorrect result due to overflow!

また、Math.pow()をまったく同じ数で使用し、次の値から返されたdoubleからintにキャストすると、何が起こるかということも注目に値しますMath.pow()

System.out.println("x^2: " + (int) (Math.pow(x, 2))); //4609609
System.out.println("y^2: " + (int) (Math.pow(y, 2))); //2147483647 - double to int conversion clamps to Integer.MAX_VALUE
System.out.println("x^2 < y^2: " + ((int) (Math.pow(x, 2)) < (int) (Math.pow(y, 2)))); //true - but for the wrong reason!

それは働いていますか?いいえ、にy*y固定されてInteger.MAX_VALUEおり、x*x未満であるため、正しい答えを出しましたInteger.MAX_VALUEx*x固定されていた場合はInteger.MAX_VALUE、間違った答えが得られます。

同様の原則は、フロートとダブル(オーバーフローする前に明らかに広い範囲を持っていることを除く)と、静かにオーバーフローを許可する他の言語にも適用されます。


ほとんどの人floatは座標にsを使用しますが、これは約10^38notの後にのみオーバーフローしintます。
ボボボボ

しかし、10 ^ 38では、精度があまりにも失われているため、距離の比較がもう有効かどうかを本当に確認することはできません。オーバーフローだけが問題ではありません。altdevblogaday.com/2012/02/05/dont-store-that-in-a-floatを参照してください(「表」セクションでは、最大10億の精度損失を要約しています)。
マキシマスミニマス

sqrt(x * x)でも同じオーバーフロー問題が発生します。私はあなたの要点がわかりません。これはマンハッタン距離などに関するものではありません。
bogglez 14

@bogglez-ライブラリ(またはCPU)がアップキャストするかどうかによって異なります。
マキシマスミニマス

3

かつて私は平方距離で作業していて、走行距離計のカウントのために平方距離の累積を間違えました。

もちろん、これを行うことはできません。数学的には、

(a^2+b^2+c^2+d^2)!=(a+b+c+d)^2

そのため、そこで間違った結果が出ました。おっとっと!


1
また、二乗距離を使用しようとしたことが何度かありましたが、同じコードブランチで実際の距離が必要になったことがわかりました。だから、無理をしないでください。sqrtとにかく操作を実行する必要がある場合、どこでも平方係数を保持する不便さの価値がない場合があります。
ボボボボ

3

最適化された位置を計算する必要があるアルゴリズムを作成している場合、問題が発生する可能性があります。たとえば、オブジェクトのセットがあり、すべてのオブジェクトから最小の合計距離で位置を計算しようとしたとしましょう。具体的な例として、3つの建物に電力を供給しようとしている場合、電線の最短距離ですべての建物に接続できるように、発電所をどこに配置すべきかを考えたいとします。距離の2乗メトリックを使用すると、発電所のx座標は、すべての建物のx座標の平均になります(y座標の場合も同様)。通常の距離メトリックを使用すると、解は異なり、多くの場合、距離の2乗解から非常に遠くなります。


特定の状況でどちらが良いか悪いかは議論の余地があるようです。数学者は、線を一連の点に当てはめるときに距離の2乗を使用することを選択することが多いことを思い出します。おそらくそれは、孤立した外れ値の影響を減らすためです。3つの建物の場合、外れ値はリスクではないかもしれません。それとも、おそらく彼らはそれをやるのx^2は、より簡単に作業できるからです|x|
joeytwiddle

@joeytwiddle Outliersは、実際には絶対距離よりも最小二乗近似により線形回帰に大きく影響します。作業しやすいので、使用するのは正しいです。私が与えた例では(多数の建物を含むように修正されている場合でも)、距離の二乗メトリックは単純な式(各座標の算術平均)で解かれますが、絶対距離メトリックは数学的に扱いにくいため、いくつかの数値的方法のうちの1つを使用して近似的に解決しました。
アレクサンダーグルーバー

修正していただきありがとうございます。当然ですが、距離の2乗は外れ値に対して大きなエラーを生成し、上で間違って述べたように、影響を減らすのではなく、影響を大きくします。これは、最小絶対距離ソリューションの計算がどれほど難しいかということです。
joeytwiddle

0

距離の2乗を使用することは、ほぼ常に問題なく、パフォーマンスに適しています。以下の考慮事項が重要です。

いくつかの距離の合計について考えたい場合、距離の2乗は不正確になります。たとえば、2つの距離があり、それらの合計が10未満であることを確認する必要があります。次のコードは正しくありません。

a = get_distance_squared(c,d);
b = get_distance_squared(e,f);
assert(a+b < 10^2);

これは、次の無効な場合にアサートする失敗しますa=36と、b=49。この場合、最初の長さは6で、2番目の長さは7です。それらの合計は10を超えていますが、二乗の合計は100以上ではありません。

別の考慮事項:実数値の距離の場合、距離の2乗は常に正になります。たとえば、変位を測定している場合、負の値を処理する必要があるかもしれませんが、それらを二乗することはできません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.