Pythonで三角関数を計算(sin, cos, tan, arcsin, arccos, arctan)
Pythonの数学関数の標準モジュールmath
を使うと、三角関数(sin, cos, tan)および逆三角関数(arcsin, arccos, arctan)の計算ができる。
ここでは、以下の内容についてサンプルコードとともに説明する。
- 円周率(パイ):
math.pi
- 角度変換(ラジアン、度):
math.degrees()
,math.radians()
- 正弦、逆正弦:
math.sin()
,math.asin()
- 余弦、逆余弦:
math.cos()
,math.acos()
- 正接、逆正接:
math.tan()
,math.atan()
,math.atan2()
math.atan()
とmath.atan2()
の違い
NumPyにおける三角関数については以下の記事を参照。
円周率(パイ): math.pi
円周率(パイ、π)はmath
モジュールの中で定数として用意されている。math.pi
で表す。
import math
print(math.pi)
# 3.141592653589793
角度変換(ラジアン、度): math.degrees(), math.radians()
math
モジュールの三角関数および逆三角関数は、角度の単位としてラジアンを使う。
ラジアン(弧度法)と度(度数法)を変換するにはmath.degrees()
とmath.radians()
を使う。
ラジアンから度に変換するのがmath.degrees()
で、度からラジアンに変換するのがmath.radians()
。
print(math.degrees(math.pi))
# 180.0
print(math.radians(180))
# 3.141592653589793
正弦、逆正弦: math.sin(), math.asin()
正弦(サイン、sin)を求める関数はmath.sin()
、逆正弦(アークサイン、arcsin)を求める関数はmath.asin()
。
30度の正弦を求める例を示す。math.radians()
で度をラジアンに変換している。
sin30 = math.sin(math.radians(30))
print(sin30)
# 0.49999999999999994
30度の正弦は0.5だが、無理数である円周率を正確に計算できないので誤差が生じる。
適当な桁数で四捨五入したい場合は、round()
関数またはformat()
メソッド、format()
関数で丸める。
round()
の返り値は数値(整数int
か浮動小数点数float
)だが、format()
の返り値は文字列str
なので注意。そのあとに計算に使うのであればround()
を用いる。
print(round(sin30, 3))
print(type(round(sin30, 3)))
# 0.5
# <class 'float'>
print('{:.3}'.format(sin30))
print(type('{:.3}'.format(sin30)))
# 0.5
# <class 'str'>
print(format(sin30, '.3'))
print(type(format(sin30, '.3')))
# 0.5
# <class 'str'>
round()
関数は第二引数に小数点以下の桁数を指定する。厳密には四捨五入ではないので注意。詳細は以下の記事を参照。
format()
メソッドとformat()
関数では書式化指定文字列の.3
の部分で小数点以下の桁数を指定している。詳細は以下の記事を参照。
比較したい場合はmath.isclose()
を使う方法もある。
print(math.isclose(sin30, 0.5))
# True
同様に0.5の逆正弦を求める例を示す。math.asin()
が返すのはラジアンなので、math.degrees()
で度に変換している。
asin05 = math.degrees(math.asin(0.5))
print(asin05)
# 29.999999999999996
print(round(asin05, 3))
# 30.0
余弦、逆余弦: math.cos(), math.acos()
余弦(コサイン、cos)を求める関数はmath.cos()
、逆余弦(アークコサイン、arccos)を求める関数はmath.acos()
。
60度の余弦と0.5の逆余弦を求める例を示す。
print(math.cos(math.radians(60)))
# 0.5000000000000001
print(math.degrees(math.acos(0.5)))
# 59.99999999999999
適当な桁で丸めたい場合は、正弦と同じくround()
またはformat()
を使えばよい。
正接、逆正接: math.tan(), math.atan(), math.atan2()
正接(タンジェント、tan)を求める関数はmath.tan()
、逆正接(アークタンジェント、arctan)を求める関数はmath.atan()
またはmath.atan2()
。math.atan2()
については後述。
45度の正接と1の逆正接を求める例を示す。
print(math.tan(math.radians(45)))
# 0.9999999999999999
print(math.degrees(math.atan(1)))
# 45.0
math.atan()とmath.atan2()の違い
math.atan()
とmath.atan2()
はどちらも逆正接を返す関数だが、引数の数と戻り値の範囲が異なる。
math.atan(x)
は引数が一つで、arctan(x)
をラジアンで返す。戻り値は-pi / 2
からpi / 2
(-90度から90度)の間になる。
print(math.degrees(math.atan(0)))
# 0.0
print(math.degrees(math.atan(1)))
# 45.0
print(math.degrees(math.atan(-1)))
# -45.0
print(math.degrees(math.atan(math.inf)))
# 90.0
print(math.degrees(math.atan(-math.inf)))
# -90.0
上の例のmath.inf
は無限大を表す。
math.atan2(y, x)
は引数が二つで、arctan(y / x)
をラジアンで返す。この角度は、極座標平面において原点から座標(x, y)
へのベクトルがx軸の正の方向となす角度(偏角)であり、戻り値は-pi
からpi
(-180度から180度)の間になる。
第2象限、第3象限での角度も正しく取得できるので、極座標平面で考える場合はmath.atan()
よりもmath.atan2()
のほうが適当。
引数の順番がx, y
ではなくy, x
なので注意。
print(math.degrees(math.atan2(0, 1)))
# 0.0
print(math.degrees(math.atan2(1, 1)))
# 45.0
print(math.degrees(math.atan2(1, 0)))
# 90.0
print(math.degrees(math.atan2(1, -1)))
# 135.0
print(math.degrees(math.atan2(0, -1)))
# 180.0
print(math.degrees(math.atan2(-1, -1)))
# -135.0
print(math.degrees(math.atan2(-1, 0)))
# -90.0
print(math.degrees(math.atan2(-1, 1)))
# -45.0
上の例のように、x軸の負の方向(y
が0でx
が負の値)はpi
(180度)となるが、y
が負のゼロのときは-pi
(-180度)となる。符号を厳密に処理したい場合は要注意。
print(math.degrees(math.atan2(-0.0, -1)))
# -180.0
負のゼロは以下のような演算の結果として発生する。
print(-1 / math.inf)
# -0.0
print(-1.0 * 0.0)
# -0.0
整数int
では負のゼロとして扱われない。
print(-0.0)
# -0.0
print(-0)
# 0
x
, y
がどちらもゼロ(原点)の場合も、その符号によって結果が異なる。
print(math.degrees(math.atan2(0.0, 0.0)))
# 0.0
print(math.degrees(math.atan2(-0.0, 0.0)))
# -0.0
print(math.degrees(math.atan2(-0.0, -0.0)))
# -180.0
print(math.degrees(math.atan2(0.0, -0.0)))
# 180.0
math.atan2()
だけでなくmath.sin()
やmath.asin()
, math.tan()
, math.atan()
など、負のゼロによって結果の符号が変わる例は他にもある。
print(math.sin(0.0))
# 0.0
print(math.sin(-0.0))
# -0.0
print(math.asin(0.0))
# 0.0
print(math.asin(-0.0))
# -0.0
print(math.tan(0.0))
# 0.0
print(math.tan(-0.0))
# -0.0
print(math.atan(0.0))
# 0.0
print(math.atan(-0.0))
# -0.0
print(math.atan2(0.0, 1.0))
# 0.0
print(math.atan2(-0.0, 1.0))
# -0.0
なお、ここまでの例はCPythonで実行した結果。他の実装や環境によっては負のゼロの扱いが異なる可能性もあるので注意。