質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

4540閲覧

2直線が平行かどうかを知るための外積をしてその結果が0かどうか判定するときのベクトル == 0.0のベクトルをどうすればいいか知りたい

退会済みユーザー

退会済みユーザー

総合スコア0

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2020/06/16 03:38

タイトル通りですが「二つの直線が平行かどうかを知るための関数isParallel();関数で まず外積をしてその結果のベクトルをどうやってif(ベクトル == 0.0){ }」すればいいか知りたいです。Length();と LengthSq();どちらを使えばいいのでしょうか?長さではないのでLengthSq();を使うと考えましたがその場合なぜこっちなのでしょうか?
※まだ関数自体が未完成なのでfloat型による誤差のif文はまだ実装してません。
参考サイトからお借りしました。
参考サイト: http://marupeke296.com/COL_3D_No0_Primitive.html

/*長さ*/ float Vector::Length() { return sqrtf( LengthSq() ); } float Vector::LengthSq() { return ((x * x) + (y * y) + (z * z)); } /*外積 ベクトル x ベクトル*/ Vector Vector::cross(Vector a, Vector b) { return Vector((a.y * b.z) - (a.z * b.y), (a.z * b.x) - (a.x * b.z), (a.x * b.y) - (a.y * b.x)); } /*平行かどうか判定*/ bool Vector::isParallel(Vector a, Vector b) { Vector r = cross(a,b); printf("a X bの外積: %.2f\n",r.LengthSq()); if(r.LengthSq() == 0) { return true; }else{ return false; } }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

Length();と LengthSq();どちらを使えばいいのでしょうか?長さではないのでLengthSq();を使うと考えましたがその場合なぜこっちなのでしょうか?

平方根は非常に重い計算ですので、長さの2乗は長さより圧倒的に速く計算できます。
よって、処理の目的からしてどちらでもよいならば、長さの2乗を使うべきです。

投稿2020/06/16 13:12

ikadzuchi

総合スコア3047

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

Length();と LengthSq();どちらを使えばいいのでしょうか?

ベクトルの長さの定義でいえば、Length() のほうを使うべきですが、
今回の場合、sqrt(x) == 0 となる必要十分条件は x == 0 なので、どちらでもよいです。

float型による誤差のif文はまだ実装してません

浮動小数点同士の比較で == を使うのは、浮動小数点演算は丸め誤差が発生するので NG です。
2つの浮動小数点数 x, y が一致するかを比較するとき、それらが十分近いかどうかで判定します。例えば、差が閾値 tol 未満かどうかで判定します。

std::abs(x - y) < tol

今回の場合、std::abs(LengthSq() - 0) < tolで、LengthSq() >= 0 なので、絶対値は不要で、LengthSq() < 0.0001f のように十分小さい値かどうかで判定すればよいでしょう。

投稿2020/06/16 03:54

編集2020/06/16 04:20
tiitoi

総合スコア21954

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2020/06/16 04:07 編集

・Length()やLengthSq()は負の値にならないと思うので,absは不要に思えます. ・比較値を決める際に,2つのベクトルの長さを用いる方が良いような気もしますが(sinθの値に対して閾値判定する的な意味で.正規化的な?),どうなんでしょう?
tiitoi

2020/06/16 04:16

コメントありがとうございます。 > Length()やLengthSq()は負の値にならないと思うので,absは不要に思えます. 確かに今回は0以上なので、abs はいらないですね。 > 比較値を決める際に,2つのベクトルの長さを用いる方が良いような気もします 確かに x, y を比較するとき、abs(x - y) < tol と絶対誤差で比較するより、abs(x - y)/abs(x) < tol のように相対誤差で比較するほがいいとかの話がありますが、丸め誤差の話になると本題から逸れてしまうので、一例として、絶対誤差の比較方法を紹介しました。
fana

2020/06/16 04:26

offtopic気味な話で恐縮でした. 「話はわかったが,じゃあその閾値って,実際いくつにするんです?」的な話への参考にでもなるかな?,的な,そんな話でした.
tiitoi

2020/06/16 04:42 編集

判定基準はこれが正解というのはないので難しいですね。 どのぐらいの精度が必要なのかによると思います。3DCG 用途であれば、要求精度は単精度でも十分なぐらいなので、判定もある程度適当でいいのではないかと思ってます。
fana

2020/06/16 04:56

本件について言えば「平行かどうか」というのは,「2つのベクトルの 成す角度θ に関しての判断」になるかな? と思ったので, sinθやcosθの値に対しての不等号を書くのが理にかなっている(?)かな,とか. とはいえ,実際上は,ベクトルのノルムによる影響が目に見えて問題にならない限りは,簡便な方法で良いだろうと思うのですが. ただ,「この閾値って何?(どんな意味の値?)」というのがあると,閾値を決める際に考えやすい的な面はあるかも感です.
fana

2020/06/16 05:06 編集

e.g. 「AとBの成す角が1度以下の場合にはもう"平行"ってことでいいや」とかいう方針を, |cross( A,B )| <= |A|*|B|*sin(1度) と書く的な. ( where, "| x |" means the norm of vector x. )
tiitoi

2020/06/16 05:07

なるほど。長さだと閾値のスケールが分かりづらいですが、角度だとわかりやすいですね。参考になりました。コメントありがとうございます。
退会済みユーザー

退会済みユーザー

2020/06/16 06:23

なるほど。if文のこんな感じにしてみたのですがこれは別に平気?なのでしょうか? #define _OX_EPSILON_ 0.000001f // 誤差 /*平行かどうか判定*/ bool Vector::isParallel(Vector a, Vector b) { Vector r = cross(a,b); printf("a X bの外積: %.2f\n",r.LengthSq()); float f = r.LengthSq(); if( -_OX_EPSILON_ < f && f < _OX_EPSILON_) { printf("自作関数 平行です。"); return true; }else{ printf("自作関数 平行はありません。"); return false; } }
tiitoi

2020/06/16 07:21

それでいいと思いますよ。 fana さんのコメントにあるように r.LengthSq() = sqrt(x^2 + y^2 + z^2) >= 0 であるので、 -_OX_EPSILON_ < f && f < _OX_EPSILON_ は f < _OX_EPSILON_ だけでもいいです。
fana

2020/06/16 07:22

・「アンダースコア+大文字 で始まるやつは予約されている」とかいうC++仕様が云々…な可能性. ・回答およびコメントでのabsに関する話を読んでるならifの条件はそうはならないだろ,とか思う. ・「平気」か否かは,最終的には自身が動作を見て決めることである.(閾値の可否が用途次第なので)
fana

2020/06/16 07:26

bool Vector::isParallel(Vector a, Vector b, float Thresh = 0.000001f) { ... if( f < Thresh ) ... } とかしておいても良いかも.
退会済みユーザー

退会済みユーザー

2020/06/16 13:02

質問ですが f <= 0.0000001f; この = つまり同じ値が来た場合もう0以上なのでelseする必要がるという見方いいのでしょうか?
tiitoi

2020/06/16 13:17

どういう意味でしょうか?「 f <= 0.0000001f; の意味は、本来は0になる値でも数値計算だと丸め誤差の影響で厳密に0にはならないから、非常に0に近い値は0であると判定しましょう」という意図の処理です。0.0000001f 以上の値が来たら、平行でないと判定されますが、それは意図どおりです。丸め誤差が大きくなって、平行であると判定してほしいものが if 文に引っかからず、平行でないと判定されてしまうのであれば、閾値をもう少し大きい値にすればよいです。
guest

0

↓の内容はダメです.うっかり2次元で考えてました.


質問の趣旨から外れますが,外積ではなく内積を使って判定するならば

Length();と LengthSq();どちらを使えばいいのでしょうか?

というのを考えなくて良いように思えます(内積はスカラーなので).

「AとBが平行か?」という問題のは,
「Aに直交するA'があるとき,A'とBは直交しているか?」という問題に置き換えることができ,
「直交しているか?」というのは「内積が0かどうか」として判定できます.

投稿2020/06/17 01:20

編集2020/06/17 01:35
fana

総合スコア11632

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

episteme

2020/06/17 01:32 編集

> 「Aに直交するA'があるとき,A'とBは直交しているか?」という問題に置き換えることができ ホント? 「X軸とY軸は直交し、Y軸とZ軸は直交してる」ので X軸とZ軸は平行ってことになるぞ?
fana

2020/06/17 01:36 編集

おおっと! なぜかナチュラルに「2次元で」考えてました…… これはいけない. 低評価を依頼する次第.(自分で低評価押せないシステムが不便)
fana

2020/06/17 01:40 編集

(だいたい,2Dならば外積はスカラー扱いやんっていう.完全に脳がバグっている.どうかしてる.)
fana

2020/06/17 11:36

Why +評価 ?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問