sin() / cos() / tan() / asin() / acos() / atan2()
| 対応: | C89(1989) |
|---|
三角関数および逆三角関数です。『<math.h>』に定義されており、引数・戻り値の角度の単位はすべてラジアンです。コンパイル時に『-lm』リンクオプションが必要な場合があります。
構文
// 正弦(サイン)を返します。引数はラジアン。 double sin(double x); // 余弦(コサイン)を返します。引数はラジアン。 double cos(double x); // 正接(タンジェント)を返します。引数はラジアン。 double tan(double x); // 逆正弦(アークサイン)を返します。戻り値は [-π/2, π/2] のラジアン。 // 引数は [-1.0, 1.0] の範囲が必要です。 double asin(double x); // 逆余弦(アークコサイン)を返します。戻り値は [0, π] のラジアン。 // 引数は [-1.0, 1.0] の範囲が必要です。 double acos(double x); // y/x の逆正接(アークタンジェント)を返します。戻り値は [-π, π] のラジアン。 // x=0 の場合も正しく計算でき、象限を判定します。 double atan2(double y, double x);
関数一覧
| 関数 | 概要 | 引数の範囲 |
|---|---|---|
| sin() | 正弦(サイン)を返します。 | 制限なし(ラジアン) |
| cos() | 余弦(コサイン)を返します。 | 制限なし(ラジアン) |
| tan() | 正接(タンジェント)を返します。 | 制限なし(±π/2 付近で無限大) |
| asin() | 逆正弦(アークサイン)を返します。 | [-1.0, 1.0] |
| acos() | 逆余弦(アークコサイン)を返します。 | [-1.0, 1.0] |
| atan2() | 2引数の逆正接を返します。象限を正しく判定します。 | 制限なし(x=0 も可) |
サンプルコード
sample_sin_cos_tan.c
#include <stdio.h>
#include <math.h>
#define DEG_TO_RAD(deg) ((deg) * M_PI / 180.0)
int main(void) {
double deg = 30.0;
double rad = DEG_TO_RAD(deg);
printf("sin(30°) = %.6f\n", sin(rad));
printf("cos(30°) = %.6f\n", cos(rad));
printf("tan(30°) = %.6f\n", tan(rad));
double x = 1.0, y = 1.0;
double angle_rad = atan2(y, x);
double angle_deg = angle_rad * 180.0 / M_PI;
printf("atan2(1, 1) = %.1f°\n", angle_deg);
double val = 0.5;
double result_deg = asin(val) * 180.0 / M_PI;
printf("asin(0.5) = %.1f°\n", result_deg);
/* 3-4-5 の直角三角形 */
double a = 3.0, b = 4.0;
double hyp = sqrt(a * a + b * b);
double angle = atan2(b, a) * 180.0 / M_PI;
printf("斜辺 = %.1f、角度 = %.2f°\n", hyp, angle);
return 0;
}
コンパイルして実行すると次のようになります。
gcc sin_cos_tan.c -o sin_cos_tan -lm ./sin_cos_tan sin(30°) = 0.500000 cos(30°) = 0.866025 tan(30°) = 0.577350 atan2(1, 1) = 45.0° asin(0.5) = 30.0° 斜辺 = 5.0、角度 = 53.13°
2D 座標変換(回転行列)
sin() と cos() を使った2D座標の回転変換はゲームやグラフィクスでよく使われます。
sin_rotate.c
#include <stdio.h>
#include <math.h>
#define DEG_TO_RAD(d) ((d) * M_PI / 180.0)
/* 点 (x, y) を原点まわりに deg 度回転します。 */
void rotate(double x, double y, double deg, double *rx, double *ry) {
double rad = DEG_TO_RAD(deg);
*rx = x * cos(rad) - y * sin(rad);
*ry = x * sin(rad) + y * cos(rad);
}
int main(void) {
double rx, ry;
rotate(1.0, 0.0, 90.0, &rx, &ry);
printf("(1, 0) を 90° 回転: (%.1f, %.1f)\n", rx, ry); /* (0, 1) */
rotate(1.0, 0.0, 45.0, &rx, &ry);
printf("(1, 0) を 45° 回転: (%.4f, %.4f)\n", rx, ry); /* (0.7071, 0.7071) */
return 0;
}
コンパイルして実行すると次のようになります。
gcc sin_rotate.c -o sin_rotate -lm ./sin_rotate (1, 0) を 90° 回転: (0.0, 1.0) (1, 0) を 45° 回転: (0.7071, 0.7071)
よくあるミス
よくあるミス: 度数法をそのまま渡す
sin()・cos()・tan() の引数はラジアンです。度数法(°)をそのまま渡すと誤った値が返ります。
sin_degree_ng.c
#include <stdio.h>
#include <math.h>
int main(void) {
/* NG: 90(度)をそのまま渡すと sin(90ラジアン) になる */
printf("NG: sin(90) = %.6f\n", sin(90.0)); /* 0.893997... */
/* OK: 度をラジアンに変換してから渡す */
printf("OK: sin(90°) = %.6f\n", sin(90.0 * M_PI / 180.0)); /* 1.000000 */
return 0;
}
修正後は次の通りです。
gcc sin_degree_ng.c -o sin_degree_ng -lm ./sin_degree_ng NG: sin(90) = 0.893997 OK: sin(90°) = 1.000000
概要
C言語の三角関数はすべてラジアンを単位として使います。度数法(°)で角度を与える場合は、事前に『deg × π / 180』の式でラジアンに変換してください。逆に、ラジアンから度数法に戻す場合は『rad × 180 / π』を使います。π の値は『M_PI』マクロ(多くの環境で利用可能)を使うのが一般的です。
『atan2(y, x)』は1引数の『atan(y/x)』と異なり、x が 0 の場合でも正しく計算でき、象限(0〜360度のどの範囲か)を正しく判定します。ベクトルの角度計算には atan() ではなく atan2() を使用してください。
asin() と acos() の引数の範囲は [-1.0, 1.0] です。範囲外の値を渡すと NaN が返ります。浮動小数点演算の誤差で範囲をわずかに超えることがあるため、入力前に確認が必要な場合があります。
その他の数学関数については『sqrt() / pow() / fabs()』や『log() / exp()』を参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。