このページでは、C言語の標準ライブラリ関数である atan
関数と atan2
関数について解説していきます。
この2つは同じような関数ですが、若干動作や引数・返却値が異なります。図形を描画するなど、2次元平面上で座標を扱うようなプログラムを作成する場合、atan2
関数の方が利用することは多いかなぁと思います。
まずは、この2つの関数それぞれについて解説し、その後にこの2つの関数間での違いについて解説していきたいと思います。
Contents
(前提知識)tan
関数とは
atan
関数と atan2
関数は tan
関数の逆関数的な関数になります。
atan
関数と atan2
関数を理解する上では、tan
関数を理解しておいた方が良いため、まずは tan
関数について簡単に説明しておきます。
tan
関数とは、一言でいえば正接を求める関数です。
もう少し直感的にいえば、下の座標の図において tan(a)
の結果は y1 / x1
となります。a
は、原点と座標 (x1
, y1
) を通過する直線と x
軸とがなす角の角度です(単位はラジアン)。
つまり、tan
関数は「角度から直線の傾きを求める関数」と考えることができます。
したがって、角度が分かっている状態で直線の傾きを求めたいような場合に tan
関数が活躍します。
atan
関数
tan
関数とは逆に、atan
関数は「直線の傾き」から角度を求める関数です。求められる角度の単位はラジアンです。
スポンサーリンク
atan
関数の宣言
atan
関数は math.h
において下記のようにプロトタイプ宣言されています。
#include <math.h>
double atan(double g);
引数 g
には「直線の傾き」を指定します。
atan
関数の返却値
atan
関数は引数 g
から求めた角度を返却します。単位は前述の通りラジアンで、-π / 2
から π / 2
の範囲の値を返却します。
atan
関数の動作
atan
関数は、傾きを引数 g
とする直線の角度を求める関数です(直線と x
軸とのなす角の角度)。
傾きとは x
の増加量に対する y
の増加量の比ですので、傾きは yの増加量 / xの増加量
によって求めることができます。
したがって、座標 (x1
, y1
) が与えられた時に、atan(y1 / x1)
により、原点と座標 (x1
, y1
) を通過する直線の角度を求めるようなこともできます。
こんな感じで、座標もしくは直線の傾きが分かってる状態で角度を求めたいような場合に atan
関数が活躍します。
スポンサーリンク
atan2
関数
atan2
関数は atan
関数と同様に角度を求める関数になります。こちらも atan
関数と同様に、求められる角度の単位はラジアンです。
ただし atan
関数では「直線の傾き」から角度を算出するのに対し、atan2
関数は「座標」から角度を求めるという点が異なります。
atan2
関数の宣言
atan2
関数も math.h
において下記のようにプロトタイプ宣言されています。
#include <math.h>
double atan2(double y, double x);
引数 y
には指定したい座標の y
軸の値、引数 x
には指定したい座標の x
軸の値を指定します。
atan2
関数の返却値
atan2
関数は引数 y
と引数 x
から求めた角度を返却します。単位は前述の通りラジアンで、-π
から π
の範囲の値を返却します。
スポンサーリンク
atan2
関数の動作
atan2
関数は引数 y
と x
に対し、原点と座標 (x
, y
) を結ぶ直線の角度を求める関数です(直線と x
軸とのなす角の角度)。
原点以外の2つの座標を結ぶ直線の角度を求めたい場合は、一方の座標が原点 (0
, 0
) に移動するように両方の座標を並行移動させてから atan2
関数を実行します。
atan
関数と atan2
関数の違い
ここまで解説してきた atan
関数と atan2
関数の最も大きな違いは「角度を算出する時に使用する値」です。
atan
関数は「直線の傾き」から角度を求めるatan2
関数は「座標」から角度を求める
ただし、直線の傾きは座標から算出することができるので、結局 atan
関数でも座標から角度を求めることができると言えそうです。
ですが、座標から算出した傾きを引数とした場合、atan
関数から得られる角度が意図しないものになることがあります。
例えば下記の2つの直線と x
軸とがなす角の角度を求めることについて考えてみましょう。
- 原点と座標 (
100
,100
) を結ぶ直線 - 原点と座標 (
-100
,-100
) を結ぶ直線
まず前者の場合、求めたい角度と直線は下の図のように表すことができます。
さらに後者の場合、求めたい角度と直線は下の図のように表すことができます。
図を見ても分かるように、前者と後者の場合とで求めたい角度は異なるはずです。より具体的にいえば、2つの角度は π
(180度)の差があるはずです。
実際に、atan2(100, 100)
と atan2(-100, -100)
の結果は下記のように異なります。約 3.14
、つまり π
の差があることが確認できます。
atan2(100, 100)
:約0.785398
(π/4
)atan2(-100, -100)
:約-2.356194
(-3π/4
)
では atan(100 / 100)
と atan(-100 / -100)
の結果はどうでしょう?結果は下記のようになりました。
atan(100 / 100)
:約0.785398
(π/4
)atan(-100 / -100)
:約0.785398
(π/4
)
結果が同じになってしまいましたね…。
両者では同じ引数を 1
を指定して atan
関数を実行することになるので、同じ結果になるのは当然ですね(100 / 100
も -100 / -100
も実行結果は 1
)。
ただ、上の図を見ても分かるように、2つの直線から求めたい角度は異なるはずです。つまりこの場合、atan
関数では本当に求めたかった角度が求められなかったことになります。
こんな感じで atan
関数の場合、座標から計算した傾きを引数に指定すると、意図しない結果となる場合があります。
atan2
関数の場合、引数で座標そのものを指定することができるため、その座標の点が原点から見てどの方向に存在するかどうかを判断して角度を算出することができます。要は x
と y
それぞれの符号を考慮して角度を算出してくれます。
その一方で atan
関数の場合、引数では直線の傾きしか指定できないので、その直線の傾きの算出元となった座標が原点から見てどの方向に存在するかどうかを判断することができません。
判断できないので、とにかく atan
関数は -π/2
から π/2
の範囲の値を返却するようになっています。
先程の例でいえば、傾きが 1
の直線が x
軸となす角の角度の候補として π/4
と -3π/4
の2つがありますが、後者は範囲外の値になるため、前者の値が返却されるようになっています。
こういった違いがあるため、単純に1次元的な値から角度を求めたいような場合は atan
関数でも良いと思いますが、二次元平面上の座標から角度を求めるような場合は atan2
関数の方が無難な場合が多いと思います。
例えば、マウスでクリックされた位置の方向をキャラクターに向かせるようなアプリやゲームを作ろうと思うと、atan
関数だとマウスでクリックされた位置とは反対の方向を向いてしまう可能性があります。
あとは図形などを描画するようなときも、座標から角度を求めるのであれば atan2
関数を用いた方が良いと思います。
atan
関数と atan2
関数の使用例と注意点
最後に atan
関数と atan2
関数の簡単な使用例とちょっとした注意点について解説しておきます。
スポンサーリンク
使用例
下記は、次の2つの直線と x
軸とがなす角の角度を atan
関数と atan2
関数それぞれで求めるプログラム例になります。
- 原点と座標 (
-100
,50
) を結ぶ直線 - 原点と座標 (
100
,50
) を結ぶ直線
#include <stdio.h>
#include <math.h>
int main(void) {
int x, y;
double a;
y = 50;
for (x = -100; x <= 100; x += 200) {
a = atan((double)y / (double)x);
printf("[atan ]原点と座標(%d,%d)を結ぶ直線の角度:%f\n", x, y, a);
}
for (x = -100; x <= 100; x += 200) {
a = atan2(y, x);
printf("[atan2]原点と座標(%d,%d)を結ぶ直線の角度:%f\n", x, y, a);
}
return 0;
}
実行結果は下記のようになります。
[atan ]原点と座標(-100,50)を結ぶ直線の角度:-0.463648 [atan ]原点と座標(100,50)を結ぶ直線の角度:0.463648 [atan2]原点と座標(-100,50)を結ぶ直線の角度:2.677945 [atan2]原点と座標(100,50)を結ぶ直線の角度:0.463648
注意点
このページの最後として、atan
関数と atan2
関数のちょっとした注意点をまとめておきます。
atan
関数と atan2
関数の返却値の単位はラジアン
atan
関数と atan2
関数の返却値の単位は “度” ではなく “ラジアン” です。
これらの関数の返却値を “度” で表したい場合、下記ページで解説しているように、返却値に対して 180 / π
を掛けてやる必要があります。
atan
関数の返却値は -π/2
から π/2
の範囲の値のみ
また、atan 関数と atan2 関数の違い で解説したように、atan
関数の返却値は -π/2
から π/2
の範囲の値のみとなります。
そのため座標から直線の傾きを計算して atan
関数を実行したとしても、原点とその座標を結ぶ直線の傾きになるとは限らないので注意してください。
この現象は、上記の 使用例 の結果からも確認できると思います。
atan
関数の引数を計算する際の型に注意
また、atan
関数の引数の値を座標から割り算で計算する場合は型に注意してください。
特に画像を扱うような場合、座標 x
や y
を表す変数には整数型が用いられることが多いです。
その一方で、C言語では 整数型 / 整数型
の結果は 整数型
であり、小数点以下の値が捨てられてしまいます。
例えば x
と y
がそれぞれ int
型の変数であるとすると、 x = 100
・y = 90
の場合に y / x
をそのまま行うと結果が 0
になり、求める傾きとして意図しないものになってしまいます。
このような場合、小数点以下の値が捨てられないよう、キャスト演算子を用いて double
型に変換してから割り算する必要があります。例えばこの例であれば、(double)y / (double)x
を実行すれば計算結果は 0.9
となり意図した結果を得ることができます。
atan2
関数の第1引数は y
座標
atan2
関数では第1引数が y
座標であることに注意してください。ついつい x
座標の方を第1引数に指定してしまうことが多いです。
例えば EXCEL でも atan2
と同様の関数が用意されており、この EXCEL の関数の場合は x
座標の方が第1引数になるらしいです…。この辺りとも混同しないように注意してください。
縦軸の正方向の向きと角度の関係に注意
このページでは、縦軸(y
軸)の正方向を上方向として解説してきましたが、プログラミングで座標を扱う場合は、縦軸の正方向が下方向であることが結構多いです。
例えば画像データなどは、原点が左上で縦軸の正方向を下方向として扱うことが多いです。
縦軸の正方向を上方向とした場合、角度の正方向は反時計回りになりますが、縦軸の正方向を下方向とした場合、角度の正方向は時計回りになるので注意してください。
まとめ
このページでは、C言語の標準ライブラリ関数である atan
関数と atan2
関数について解説しました!
両者ともに角度を求めるための関数になりますが、atan
関数は「直線の傾き」から、atan2
関数は「座標」から角度を求めるという違いがあります。
また、この違いがあるため、引数や返却値も異なります。
さらに、atan
関数では直線の傾きのみから角度を算出するため、座標値 x
と y
の符号を考慮せずに角度が求められてしまうことに注意してください。
二次元平面上の座標から角度を求めたいような場合は、atan2
関数の方が適していることが多いと思います。なので、特に atan2
関数の使い方はマスターしておきましょう!