3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「割って掛ける」と「掛けて割る」は同じ計算ではない

Posted at

同じ計算と主張しているのに計算結果が違う

なでしこさんの「座標角度計算」関数は、配列 [x座標, y座標] を受け取り、原点からその点に向かう半直線がx軸の正の方向となす角を度単位で返す関数である。

この関数の使用例に、以下の記述がある。

全て同じ計算をしています。

x=100。y=50。
[x,y]の座標角度計算して表示。
ARCTAN(y/x)を度変換して表示。
ATAN2(y,x)を度変換して表示。

しかし、これを v3.6.41 で実行した結果は、以下のようになった。

26.56505117707799
26.565051177077986
26.565051177077986

本当に同じ計算をしているのであれば、同じ結果になるのが自然である。
しかし、実際には微妙に違う結果になっている。
なぜだろうか?

ソースを見てみる

「座標角度計算」の解説からリンクが張られているソースコードを見てみよう。

nadesiko3core/src/plugin_math.mts at main · kujirahand/nadesiko3core

すると、上で引用した使用例で用いられている関数では、以下の計算をしていることがわかる。

関数 計算内容
ARCTAN Math.atan(v)
ATAN2 Math.atan2(y, x)
座標角度計算 Math.atan2(XY[1], XY[0]) * 180 / Math.PI
度変換 v / Math.PI * 180

逆正接 (atanatan2) を求める部分は実質同じであるようだが、ラジアンから度に変換する部分が違っている。
「度変換」では円周率で割ってから 180 を掛けているのに対し、「座標角度計算」では 180 を掛けてから円周率で割っている

この違いがあるため、入力する数値によって誤差の出方が変わり、異なる結果となりうるようである。

値の差を詳しく確認してみる

C言語で同様の計算をしてみた。

#include <stdio.h>
#include <math.h>

#define PI 3.1415926535897932384626

int main(void) {
	double x = 100, y = 50;
	printf("%a\n", atan2(y, x) * 180 / PI);
	printf("%a\n", atan2(y, x) / PI * 180);
	return 0;
}

実行すると、以下の結果が得られた。

0x1.a90a731a61dc4p+4
0x1.a90a731a61dc3p+4

やはり、計算結果の違いは浮動小数点数の最後の1桁分のようである。

計算結果が同じになる例

引用した使用例で、 の値を 100 から 110 に変えてみると、「割って掛ける」と「掛けて割る」の計算結果が 24.443954780416536 で一致する。

C言語で確認してみる と、計算結果は 0x1.871a7053ecab9p+4 で一致していることがわかる。

結論

内部では異なる計算を行い、それによって実際に計算結果が変わる使用例を示しておきながら、「同じ計算をしています」という嘘の主張をしているのは、カッコ悪いと思う。

3
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?