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

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

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

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

Q&A

解決済

4回答

5859閲覧

緯度経度から距離を算出したい

gyosh2018.08.07

総合スコア8

C++

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

0グッド

0クリップ

投稿2018/08/07 06:24

編集2018/08/08 00:19

前提・実現したいこと

緯度経度から距離を算出する式
https://teratail.com/questions/90662
回答の「コードをぱぱっと置いときます。」で、def azimuth(x1, y1, x2, y2):は、正しく動作しましたが、
def distance(x1, y1, x2, y2, r):で距離を求めると、0.129にならず、ゼロになります。
両方の関数とも、CCS C に移植して動作させました。
MPLAB IDE v8.70 の MPLAB SIMでデバックテスト。ターゲットCPU未使用。

発生している問題・エラーメッセージ

エラーメッセージ 無し

該当のソースコード

CCS C
float distance(x1, y1, x2, y2) {
float _x1, _y1, _x2, _y2, a, b, c, d, tmp ,r;
r = 6378.137e3; //地球半径
_x1 = x1 * pi/180;
_y1 = y1 * pi/180;
_x2 = x2 * pi/180;
_y2 = y2 * pi/180;
a = _x2 - _x1;
b = sin(_y1) * sin(_y2);
c = cos(_y1) * cos(_y2) * cos(a);
d = b + c;
tmp = r * acos(d);
return tmp;
}
//メイン
float dis; //目標地までの距離
dis = distance(Tookei_S,Hokui_S, TookeiWP_S, HokuiWP_S) / 1e3; //Kmに変換。

試したこと

オリジナルの関数を変数で分解して関数電卓で検算しても結果は同じ。

★その後の状況
電卓を使って手計算してみた結果
Do2Ra = PI/180 = 0.0174532925199433として計算
_x1 = Tookei_S * Do2Ra; //2.426007660272119
_y1 = Hokui_S * Do2Ra; //0.6108652381980155
_x2 = TookeiWP_S * Do2Ra; //2.443460952792062
_y2 = HokuiWP_S * Do2Ra; //0.6283185307179588
Dx = _x2 - _x1; //0.017453292519943
val = sin(_y1) * sin(_y2) + cos(_y1) * cos(_y2) * cos(Dx); //Val
//以下部分的に電卓で計算
//sin(_y1) =0.01066140770962710955720304810472
//sin(_y2) =0.01096600731730257117720846470937
//cos(_y1) =0.99994316557774877549975045573468
//cos(_y2) =0.99993987153404222401529954032816
//cos(Dx) =0.99999995360411414000869052659551
//sin(_y1) * sin(_y2) = 0.0109660073173025
//cos(_y1) * cos(_y2) * cos(Dx) = 0.9998829941386981
//val = 1.010849001456001
dis = 6378.137 * acos(val); //地球半径
//acos(val) 1 より大きいので計算不能でゼロになる。従って disはゼロ

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

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

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

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

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

guest

回答4

0

floatだと桁落ち誤差でdが1になってtmpが0になってしまいます。
doubleにするか別のアルゴリズムを探すかです。

今回のような近距離だと、大円距離ではなく直線距離で近似するか、
wikipediaの大円距離のコンピュータによる計算を使うかです。

C

1#include <stdio.h> 2#include <math.h> 3 4float distance(float x1, float y1, float x2, float y2, float r){ 5 float pi = 3.1415926535897932384626433832795; 6 x1 *= pi/180; 7 y1 *= pi/180; 8 x2 *= pi/180; 9 y2 *= pi/180; 10 11 float dx = x2 - x1; 12 float dy = y2 - y1; 13 float sy = sin(dy/2.0); 14 float sx = sin(dx/2.0); 15 float sigma = sy*sy + cos(y1)*cos(y2)*sx*sx; 16 return r *2.0*asin(sqrt(sigma)); 17 18} 19 20int main(void){ 21 float x1 = 139.988909; 22 float y1 = 35.685828; 23 float x2 = 139.990339; 24 float y2 = 35.685879; 25 float r = 6378.137e3; 26 27 printf("%f",distance(x1,y1,x2,y2,r)/1e3); 28}

投稿2018/08/07 06:42

編集2018/08/08 06:28
ozwk

総合スコア13512

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

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

gyosh2018.08.07

2018/08/07 07:19

早速ご回答頂き有難うございました。 CCS C はDoubleが未サポートなのですが、floatをdubleに入れ替えてもコンパイルエラーにならないのでやってみました。結果はゼロでは無くなりましたが、10018.7539になり、0.129になりません。
ardin

2018/08/08 06:14

せっかく、検算したのですし debug状態にして、breakで逐一止めて計算がどこまであっているのか調べるのが早いかと思います。
guest

0

C++ タグ付いているけど実際には C なので、

C

1float distance(x1, y1, x2, y2) { 2

x1, y1, x2, y2 がすべて int 扱いになっていませんか?

投稿2018/08/07 10:28

daisuke7

総合スコア1563

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

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

pepperleaf

2018/08/07 11:44

VC++ 2017でコンパイルしたら、確かにそう。 昔々の C言語の仕様が未だに生きているなんて、、、、。 (省略時は、 int と見なす) 引数の宣言を float にして、 float --> double としたら、期待する結果になるみたいですね。
gyosh2018.08.07

2018/08/07 18:15

すみません。doubleにしても結果が間違っています。
daisuke7

2018/08/07 18:20

double distance(double x1, double y1, double x2, double y2) { のように、引数の型も double にしてますか?
guest

0

自己解決

みなさんご親切にご回答頂きまして有難うございました。
距離を計算する方法は、マイコンPIC18F4580とCCS C コンパイラで色々とやりましたが、計算精度の問題で正しく計算できませんでした。
やりたいことは目標地に近づいたかどうかなので、目標地と現在地の緯度経度を秒に換算して、0.1秒以下の範囲に入ったら目標地点に到着と判断する方法にしました。テストしているGPSユニットは秋月電子製ですが、大まかに半径2mの精度でした。
お騒がせしてしまい申し訳ございませんでした。
ありがとうございました。

投稿2018/08/16 21:56

gyosh2018.08.07

総合スコア8

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

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

0

C

1double distance(double x1, double y1, double x2, double y2) 2{ 3 const double pi = 3.141592653589793238462643383279502884197169399375105820974; 4 double _x1, _y1, _x2, _y2, a, b, c, d, tmp, r; 5 r = 6378.137e3; //地球半径 6 _x1 = x1 * pi / 180; 7 _y1 = y1 * pi / 180; 8 _x2 = x2 * pi / 180; 9 _y2 = y2 * pi / 180; 10 a = _x2 - _x1; 11 b = sin(_y1) * sin(_y2); 12 c = cos(_y1) * cos(_y2) * cos(a); 13 d = b + c; 14 tmp = r * acos(d); 15 return tmp; 16} 17 18//メイン 19int main() 20{ 21 double Tookei_S = 139.988909; //目標地までの距離 22 double Hokui_S = 35.685828; //目標地までの距離 23 double TookeiWP_S = 139.990339; //目標地までの距離 24 double HokuiWP_S = 35.685879; //目標地までの距離 25 double dis = distance(Tookei_S, Hokui_S, TookeiWP_S, HokuiWP_S) / 1e3; //Kmに変換。 26}

VS2017 x86 debugモード
floatを全部double型にして実行してみましたが、
0.129・・・・
のようになりました。

_y1 = Hokui_S * Do2Ra; //0.6108652381980155
ここの計算が合わないですね。
0.62283519490038297になるようです。

投稿2018/08/08 06:32

ardin

総合スコア544

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

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

gyosh2018.08.07

2018/08/08 21:18

教えて頂いたソースをそのまま実行しましたが結果はゼロになりました。 _y1 = Hokui_S * Do2Ra;の計算は、Windows付属の電卓で計算した結果です。電卓の精度が悪いのでしょうか。 最初に書かなかったのですが、今回のターゲットはPICマイコンで開発はMPLAB IDE v8.70です。 言語は C CCS C コンパイラーです。doubleは使えるのですが保証外になっています。 電卓による計算が間違っているかもしれません。
ardin

2018/08/09 00:14 編集

Windows10付属の電卓で計算した結果 _y1 = Hokui_S * Do2Ra;→ _y1 = y1 * pi / 180; 0.62283519490038302257411597889472 となりますね。 Do2Raが違うと他も変わるはずなので、Hokui_Sの値があっているか怪しいような。 0.6108652381980155となるためには、Hokui_Sは35.000・・・になりそうです。
ardin

2018/08/09 00:02 編集

ちなみに普通の卓上電卓でも 35.685828*3.14159/180=0.6228346688 となったので、Hokui_Sにあたる値が間違っている可能性が大のように思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問