double型-0の謎

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
こもりん

double型-0の謎

#1

投稿記事 by こもりん » 7年前

初めまして。早速ですがテンプレに則って、質問を投稿させて頂きます
[1] 質問文
 [1.1] 自分が今行いたい事は何か
やりたかったことは以下の通りです。
①ある3点の3次元座標を指定する
②その3点が通る平面の法線ベクトルを求める
③その法線ベクトルをどのくらいの角度で回転させればz軸単位ベクトル(0,0,1)と重なるか調べる
これを実装しようとしました。
だいたいやりたいことはできるようにコードを書くことはできましたが、何点か細かい疑問点が出たので投稿します。
 [1.2] どのように取り組んだか(プログラムコードがある場合記載)
一番最後に記載します
 [1.3] どのようなエラーやトラブルで困っているか(エラーメッセージが解る場合は記載)
出力結果より  単位ベクトル -0,1,-0  というように0の結果にマイナスがつくことが有る
今後内積などを求めるときに、この-0が計算結果に悪影響を及ぼす可能性があります。
 [1.4] 今何がわからないのか、知りたいのか
(i)-0が出てしまう原因(なんとなく分かっているつもりですが……)と、
 -0を0とみなして計算するにはどのようにコードを書けばよろしいでしょうか?
 いちいちif文で==-0なら0にするみたいにしないといけないのでしょうか?
(ii)
 こんかいごり押しで書いている部分。
 外積内積のライブラリ等があればご紹介いただけたら幸いです。
(iii)
 初心者ゆえ、汚いコードとなっておりますので、簡略化できる箇所などあったらアドバイス頂けたら幸いです
 9個の要素と配列を引数にした関数って美しいといえるのかわからないですorz

以上、長くなりましたがお手すきの際にお答えいただけたら幸いです。
よろしくお願いいたします

コード:

#include <iostream>
#include <math.h>
#include <string>

#include "ResliceVTI.h"

using namespace std;

//3つの点より外積ベクトル(外積ベクトルはy軸正方向を取るようにする)の角度を求める関数
void *GetCrossProductVectorAngle(int x1, int y1, int z1,
	int x2, int y2, int z2,
	int x3, int y3, int z3, double rad[3]) {

	int alpha[3] = { x2 - x1, y2 - y1, z2 - z1 };
	int beta[3] = { x3 - x1, y3 - y1, z3 - z1 };
	double crossProductVectorAngle[3];
	crossProductVectorAngle[0] = (alpha[1] * beta[2] - alpha[2] * beta[1]);
	crossProductVectorAngle[1] = (alpha[2] * beta[0] - alpha[0] * beta[2]);
	crossProductVectorAngle[2] = (alpha[0] * beta[1] - alpha[1] * beta[0]);
	double lng_CPVA = sqrt(crossProductVectorAngle[0] * crossProductVectorAngle[0] +
		crossProductVectorAngle[1] * crossProductVectorAngle[1] +
		crossProductVectorAngle[2] * crossProductVectorAngle[2]);
	//単位ベクトルに直す
	double unit_CPVA[3];
	unit_CPVA[0] = crossProductVectorAngle[0] / lng_CPVA;
	unit_CPVA[1] = crossProductVectorAngle[1] / lng_CPVA;
	unit_CPVA[2] = crossProductVectorAngle[2] / lng_CPVA;

	if (unit_CPVA[1] < 0){
		unit_CPVA[0] = unit_CPVA[0] * -1;
		unit_CPVA[1] = unit_CPVA[1] * -1;
		unit_CPVA[2] = unit_CPVA[2] * -1;
	}

	cout << "単位ベクトル " << unit_CPVA[0] << "," << unit_CPVA[1] << "," << unit_CPVA[2] << endl;

	rad[1] = asin(unit_CPVA[0]);
	rad[0] = 0;
	if (cos(rad[1]) != 0) {
		rad[0] = asin(-1 * unit_CPVA[1] / cos(rad[1]));
	}
	rad[2] = 0;

	//逆回転を求めるためー1倍
	rad[0] = -1 * rad[0];
	rad[1] = -1 * rad[1];

	return rad;
}

void main(int argc, char** argv) {

	cout << "座標を3つ入れてください(x1 y1 z1 x2 y2 z2 x3 y3 z3)スペース区切り" << endl;
	int x1, x2, x3, y1, y2, y3, z1, z2, z3;
	//cin >> x1 >> y1 >> z1 >> x2 >> y2 >> z2 >> x3 >> y3 >> z3;
	//cout <<"入力 "<< x1 << " " << y1 << " " << z1 << " " << x2 << " " << y2 << " " << z2 << " " << x3 << " " << y3 << " " << z3 << endl;
	x1 = 45;
	y1 = 100;
	z1 = 120;
	x2 = 153;
	y2 = 100;
	z2 = 10;
	x3 = 200;
	y3 = 100;
	z3 = 60;

	//3つの点より外積ベクトルの角度を求める関数
	double rad[3];
	GetCrossProductVectorAngle(x1, y1, z1,
							   x2, y2, z2,
							   x3, y3, z3,rad);

	cout << "x軸回転" << rad[0] << " y軸回転" << rad[1] << " z軸回転" << rad[2] << endl;
	system("PAUSE");
}

[2] 環境  
 [2.1] OS : Windows10
 [2.2] コンパイラ名 : visualstudio 2013
[3] その他
 ・自分のコンパイラ名すらわからない初心者です……orz

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: double型-0の謎

#2

投稿記事 by usao » 7年前

> (i)
原因は,30行目~で,0に -1 を乗じたからでしょうかね.

値が十分に0に近いか否かを判定したいのであれば,
絶対値が十分に小さいかどうか,という判定を行えば良いのではないでしょうか.

>(iii)
(引数よりも戻り値の謎具合の方が気になりますが…)
>3次元座標
を表す型を用意すれば,引数も見た目4個になるでしょうし,
ベクトル関係の処理関数(外積,定数倍,ノルムの計算…)を書くのも楽になるかと思います.
(まぁ,(ii)に関する良い回答が得られれば,そこらへんはライブラリが用意しているものを使う形になるのでしょうが)

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: double型-0の謎

#3

投稿記事 by usao » 7年前

オフトピック
ちょっとググったら,+=0 すれば -0を0にできるという話が.

トニ
記事: 4
登録日時: 8年前

Re: double型-0の謎

#4

投稿記事 by トニ » 7年前

過去にログインしたIDとパスワードが残ってたのでそちらから返信いたします。

>>usaoさん
ご回答ありがとうございました。
戻り値のポインタ(?)はミスですね。なんでビルド通ってたのかさっぱりです。
*を削除しました。

+=0を計算毎の末端に書けば、今回のような事故をふせげそうですね。
毎回if文<0.0000001とかやらないで済みそうなので助かります。

ライブラリの情報を書いてくださる方がいらっしゃるかもしれないので、誠に勝手ですが、
あと一週間ほどはトピックを「解決!」せずに残しておきたいです。
ご了承ください・・・。

また自分でも探してみます。

返信

“C言語何でも質問掲示板” へ戻る