同じ計算と主張しているのに計算結果が違う
なでしこさんの「座標角度計算」関数は、配列 [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 |
逆正接 (atan
・atan2
) を求める部分は実質同じであるようだが、ラジアンから度に変換する部分が違っている。
「度変換」では円周率で割ってから 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桁分のようである。
計算結果が同じになる例
引用した使用例で、x
の値を 100
から 110
に変えてみると、「割って掛ける」と「掛けて割る」の計算結果が 24.443954780416536
で一致する。
C言語で確認してみる と、計算結果は 0x1.871a7053ecab9p+4
で一致していることがわかる。
結論
内部では異なる計算を行い、それによって実際に計算結果が変わる使用例を示しておきながら、「同じ計算をしています」という嘘の主張をしているのは、カッコ悪いと思う。