プログラミングで図形や物体の動きを扱うとき、三角関数は避けて通れない重要な道具です。
特にC言語では、標準ライブラリに用意された関数を使うことで、角度から長さを求めたり、座標を計算したりできます。
本記事では、三角関数(sin・cos・tan)の基本的な意味と、C言語での具体的な計算方法を、初心者の方にも分かりやすいように順を追って解説します。
三角関数とは何か
三角関数(sin・cos・tan)の意味と役割
三角関数とは、角度と長さの比(三角比)の関係を表す関数の総称です。
特に、次の3つが最もよく使われます。
- sin(サイン)
- cos(コサイン)
- tan(タンジェント)
これらは、もともと直角三角形の辺の長さの比として定義されました。
C言語の関数sin・cos・tanは、まさにこの三角関数を計算するための関数です。
三角関数の役割を、用途の観点から整理すると次のようになります。
| 関数名 | 読み方 | 主な意味・用途 |
|---|---|---|
| sin | サイン | 角度から「高さ方向」の比を求める。波(音、光)、振動の計算などで利用 |
| cos | コサイン | 角度から「横方向」の比を求める。回転や位置座標の計算で利用 |
| tan | タンジェント | 「高さ÷横」の比。傾きや勾配の計算で利用 |
回転・角度・方向・周期的な動きが出てくる場面では、ほぼ必ず三角関数が関わってきます。
ゲーム開発や図形処理でも、プレイヤーの向きから座標を計算したり、カメラの角度から視線方向を求めるときなどに多用されます。
直角三角形と三角比の関係
三角関数の直感的な理解には、直角三角形をイメージすると分かりやすいです。
角度θを含む直角三角形を考え、辺の呼び方を次のようにします。
- 斜辺: 直角をはさむ2辺のうち、最も長い辺
- 対辺: 角
θの向かい側の辺 - 隣辺: 角
θに隣接する、斜辺ではない方の辺
このとき、三角比は次のように定義されます。
| 三角関数 | 定義(直角三角形の辺の比) |
|---|---|
| sinθ | 対辺 ÷ 斜辺 |
| cosθ | 隣辺 ÷ 斜辺 |
| tanθ | 対辺 ÷ 隣辺 |
sinとcosは、必ず斜辺を分母に持つ比です。
そのため、斜辺の長さを1としたとき、sinとcosの値は必ず-1から1の範囲に収まります。
一方でtanは隣辺が分母なので、値が非常に大きくなったり、定義できない角度も出てきます。
この点は、後の「tanの計算で注意すべき角度」で詳しく説明します。
単位円と角度(度数法・弧度法)の違い
より一般的に三角関数を扱うために、単位円という考え方が使われます。
これは、次のような円です。
- 中心が原点(0,0)
- 半径が1
この単位円上の点の座標と角度θの関係は、次のように表されます。
- x座標 = cosθ
- y座標 = sinθ
つまり三角関数は、円周上の点の位置を表しているとも言えます。
C言語で三角関数を使って座標を計算する場合、この関係をそのまま利用することが多いです。
ここで重要になるのが、角度の表し方です。
角度には主に次の2種類の表現があります。
| 表現方法 | 名称 | 例 | 特徴 |
|---|---|---|---|
| 60° など | 度数法(degree) | 0°〜360° | 日常的な角度表現 |
| π/3 など | 弧度法(radian, rad) | 0〜2π | 数学・プログラミング向け |
C言語の三角関数は、すべて弧度法(rad)で角度を扱います。
例えば「30度のsin」を計算したい場合、そのままsin(30)とは書かず、30°をラジアンに変換してからsinに渡す必要があります。
この角度変換については後ほど詳しくコード付きで説明します。
C言語で三角関数を使う準備
math.hヘッダーファイルのインクルード方法
C言語でsin・cos・tanなどの三角関数を使うには、標準ライブラリのmath.hをインクルードする必要があります。
基本的な書き方は次の通りです。
#include <stdio.h> // 入出力関数の宣言
#include <math.h> // 三角関数やsqrtなど数学関数の宣言
int main(void) {
double x = 0.5;
double y = sin(x); // sin関数を使用
printf("sin(0.5) = %f\n", y);
return 0;
}
このように#include <math.h>を書くことで、コンパイラはsinやcosなどの関数宣言を認識できるようになります。
ヘッダーファイルをインクルードしないと、コンパイル時に警告やエラーが出るので注意してください。
コンパイル時のリンクオプション(-lm)について
多くの環境(GCCなど)では、数学ライブラリは別途リンク指定が必要です。
そのため、ただコンパイルするだけではなく、-lmというオプションを付けてリンクを行います。
GCCの例を示します。
// sample_trig.c
#include <stdio.h>
#include <math.h>
int main(void) {
double x = 1.0;
printf("sin(1.0) = %f\n", sin(x));
return 0;
}
このプログラムをコンパイル・実行する場合は、次のようにします。
gcc sample_trig.c -lm -o sample_trig
./sample_trig
sin(1.0) = 0.841471
-lmを付け忘れると、リンク時に「未定義参照(undefined reference)」といったエラーが出ることがあります。
特にLinux環境でGCCを使う場合は、必ず意識しておくと良いです。
Windowsの統合開発環境(Visual Studioなど)では、自動的にリンクされることもありますが、開発環境ごとの仕様は確認しておくと安心です。
double型とfloat型の使い分け
三角関数の引数や戻り値の型としては、double型が基本です。
math.hで定義されている標準の三角関数は、次のような型を持ちます。
double sin(double x);double cos(double x);double tan(double x);
つまり引数も戻り値もdoubleです。
float型を使いたい場合は、次の選択肢があります。
- floatをdoubleに自動変換して使う
floatで角度を持っていても、関数呼び出し時に自動でdoubleに拡張されます。 - float版の関数(sinf, cosf, tanf)を使う
math.hには、float用の関数も用意されています。
| 用途 | 関数名 | 引数型 | 戻り値型 |
|---|---|---|---|
| 通常(倍精度) | sin, cos, tan | double | double |
| 単精度(float) | sinf, cosf, tanf | float | float |
初心者の方には、まずはdouble型と標準のsin・cos・tanを使うことをおすすめします。
精度も高く、エラーも起こりにくいためです。
ゲームなどでメモリや速度を強く意識するときに、必要に応じてfloatやsinfなどを検討するとよいでしょう。
C言語でのsin・cos・tanの計算方法
sin関数の使い方とコード例
sin関数は、ラジアン(rad)で表された角度の正弦(サイン)を計算する関数です。
関数の宣言は次のようになっています。
double sin(double x);
(xはラジアン単位の角度)
次のコードでは、いくつかの角度のsin値を計算してみます。
#define _USE_MATH_DEFINES // M_PIを有効にするための定義
#include <stdio.h>
#include <math.h>
// 角度(度)をラジアンに変換する関数
double deg2rad(double degree) {
// πは後ほど詳しく説明しますが、ここではM_PIを仮定
return degree * M_PI / 180.0;
}
int main(void) {
double deg30 = 30.0;
double deg90 = 90.0;
// 度をラジアンに変換
double rad30 = deg2rad(deg30);
double rad90 = deg2rad(deg90);
// sin関数で計算
double s30 = sin(rad30);
double s90 = sin(rad90);
printf("sin(30°) = %f\n", s30); // 理論値は0.5
printf("sin(90°) = %f\n", s90); // 理論値は1.0
return 0;
}
sin(30°) = 0.500000
sin(90°) = 1.000000
ここでのポイントは必ず「度」から「ラジアン」に変換してからsinを呼び出している点です。
直接sin(30.0)と書くと、「30ラジアン」のsinを計算してしまい、まったく違う結果になります。
cos関数の使い方とコード例
cos関数は、ラジアン角の余弦(コサイン)を計算する関数です。
double cos(double x);
cosは、単位円上のx座標に対応しているため、回転したときの横方向の成分を求める場面でよく使われます。
次のコードでは、0°・60°・180°のcos値を計算してみます。
#define _USE_MATH_DEFINES // M_PIを有効にするための定義
#include <stdio.h>
#include <math.h>
double deg2rad(double degree) {
return degree * M_PI / 180.0;
}
int main(void) {
double deg0 = 0.0;
double deg60 = 60.0;
double deg180 = 180.0;
double rad0 = deg2rad(deg0);
double rad60 = deg2rad(deg60);
double rad180 = deg2rad(deg180);
double c0 = cos(rad0); // cos(0°) = 1
double c60 = cos(rad60); // cos(60°) = 0.5
double c180 = cos(rad180); // cos(180°) = -1
printf("cos(0°) = %f\n", c0);
printf("cos(60°) = %f\n", c60);
printf("cos(180°) = %f\n", c180);
return 0;
}
cos(0°) = 1.000000
cos(60°) = 0.500000
cos(180°) = -1.000000
このように、cosの値は-1〜1の範囲で、角度に応じて滑らかに変化します。
位置や向きの計算では、sinとcosをセットで使うことが多いです。
tan関数の使い方とコード例
tan関数は、ラジアン角の正接(タンジェント)、つまり「sin÷cos」を計算する関数です。
double tan(double x);
tanは、傾きと深い関係があります。
例えば、ある線の傾きがtanθで表されるため、グラフの傾きや勾配を扱うときに出てきます。
まずは基本的な計算例を見てみます。
#define _USE_MATH_DEFINES // M_PIを有効にするための定義
#include <stdio.h>
#include <math.h>
double deg2rad(double degree) {
return degree * M_PI / 180.0;
}
int main(void) {
double deg0 = 0.0;
double deg45 = 45.0;
double rad0 = deg2rad(deg0);
double rad45 = deg2rad(deg45);
double t0 = tan(rad0); // tan(0°) = 0
double t45 = tan(rad45); // tan(45°) = 1
printf("tan(0°) = %f\n", t0);
printf("tan(45°) = %f\n", t45);
return 0;
}
tan(0°) = 0.000000
tan(45°) = 1.000000
tanは後述するように値が非常に大きくなったり、定義できない角度も存在します。
そのため、C言語でtanを扱うときは、cosが0に近い角度を避けるなどの注意が必要です。
角度(度)をラジアン(rad)に変換する方法
前述の通り、C言語の三角関数はすべてラジアンで角度を扱うため、「度からラジアンへの変換」は必須です。
度とラジアンの基本的な関係は次の通りです。
- 180° = π rad
これをもとに、一般的な変換式は次のようになります。
- 度→ラジアン:
rad = degree * π / 180 - ラジアン→度:
degree = rad * 180 / π
C言語での実装例を示します。
#define _USE_MATH_DEFINES // M_PIを有効にするための定義
#include <stdio.h>
#include <math.h>
// 度をラジアンに変換
double deg2rad(double degree) {
return degree * M_PI / 180.0;
}
// ラジアンを度に変換
double rad2deg(double radian) {
return radian * 180.0 / M_PI;
}
int main(void) {
double degree = 60.0;
double radian = deg2rad(degree);
printf("%f 度 = %f ラジアン\n", degree, radian);
double back_to_deg = rad2deg(radian);
printf("%f ラジアン = %f 度\n", radian, back_to_deg);
return 0;
}
60.000000 度 = 1.047198 ラジアン
1.047198 ラジアン = 60.000000 度
このように専用の変換関数を用意しておくと、プログラム中で「これは度かラジアンか」を意識しやすくなり、バグの予防にもつながります。
円周率(M_PI)と自分で定義する方法
三角関数や角度変換では、円周率π(pi)が頻繁に登場します。
C言語では、環境によってはmath.hでM_PIという定数が使える場合があります。
ただし、M_PIは標準Cの必須仕様ではなく、環境によっては定義されていないことに注意が必要です。
そのため、自分でπを定義しておく方法がよく使われます。
次のコードは、M_PIが未定義の場合に自前で定義する例です。
#define _USE_MATH_DEFINES // M_PIを有効にするための定義
#include <stdio.h>
#include <math.h>
// M_PI が定義されていない環境向けに、自分で定義しておく
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
double deg2rad(double degree) {
return degree * M_PI / 180.0;
}
int main(void) {
double degree = 180.0;
double radian = deg2rad(degree);
printf("π は約 %f です\n", M_PI);
printf("%f 度 = %f ラジアン\n", degree, radian);
return 0;
}
π は約 3.141593 です
180.000000 度 = 3.141593 ラジアン
このようにπをマクロで定義しておくと、どの環境でも安定して同じ値を使えるため、角度変換や三角関数の計算が安心して行えます。
三角関数計算の応用と注意点
三角関数の戻り値の範囲と精度
C言語の三角関数を正しく使うためには、関数の戻り値の範囲を理解しておくことが重要です。
| 関数 | 引数(ラジアン) | 戻り値の主な範囲 |
|---|---|---|
| sin | 任意の実数 | -1.0 〜 1.0 |
| cos | 任意の実数 | -1.0 〜 1.0 |
| tan | cosが0でない角度 | -∞ 〜 +∞ (理論上) |
sinとcosは必ず-1〜1の範囲に収まるので、値のチェックや正規化などに便利です。
一方tanは、角度によって非常に大きな値になることがあるので、オーバーフローや数値の不安定に注意する必要があります。
また、三角関数は浮動小数点演算で計算されるため、理論値と完全に一致しない場合があります。
例えば、理論上0であるはずのsin(π)を計算しても、実際にはごく小さい誤差が現れます。
#define _USE_MATH_DEFINES // M_PIを有効にするための定義
#include <stdio.h>
#include <math.h>
int main(void) {
double s = sin(M_PI); // 理論値は0
printf("sin(π) = %.20f\n", s); // 小数点以下20桁まで表示
return 0;
}
sin(π) = 0.00000000000000012246
このように、浮動小数点では「0と思っていた値が厳密には0でない」ことがよくあります。
そのため、「sin(x)が0かどうか」を判定したいときには、次のようにある程度の許容量(イプシロン)を持たせて比較するのが一般的です。
#define _USE_MATH_DEFINES // M_PIを有効にするための定義
#include <stdio.h>
#include <math.h>
int main(void) {
double s = sin(M_PI);
double eps = 1e-10; // 許容誤差
if (fabs(s) < eps) {
printf("ほぼ0とみなせます\n");
} else {
printf("0ではありません (s = %f)\n", s);
}
return 0;
}
ほぼ0とみなせます
このような数値誤差の扱いは、三角関数に限らず浮動小数点計算全般で重要なポイントです。
tanの計算で注意すべき角度
tan関数は、cosが0になる角度で定義できません。
具体的には、次のような角度です。
- 90°(π/2 rad)
- 270°(3π/2 rad)
- それに180°(π rad)を足した角度(…,-270°,-90°,90°,270°,450°,…)
これらの角度に近づくと、tanの値は非常に大きくなり、数値的に不安定になります。
C言語でtanを使うときは、こうした危険な角度を避ける工夫が必要です。
次の例では、90°に近づくとtanの値が急激に大きくなる様子を確認します。
#define _USE_MATH_DEFINES // M_PIを有効にするための定義
#include <stdio.h>
#include <math.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
double deg2rad(double degree) {
return degree * M_PI / 180.0;
}
int main(void) {
// 85°から89°までのtan値を表示
for (int d = 85; d <= 89; d++) {
double rad = deg2rad((double)d);
double t = tan(rad);
printf("tan(%d°) = %f\n", d, t);
}
return 0;
}
tan(85°) = 11.430052
tan(86°) = 14.300666
tan(87°) = 19.081137
tan(88°) = 28.636254
tan(89°) = 57.289962
90°に近づくにつれて、tanの値がどんどん大きくなっていることが分かります。
プログラム上では、角度が危険な範囲に入っていないか事前にチェックする、あるいは代わりにsinとcosを使って自分で比を計算し、閾値を設けるなどの工夫が必要になる場合があります。
逆三角関数(asin・acos・atan)の概要
三角関数に対応する「逆関数」として、逆三角関数があります。
C言語のmath.hには、次の関数が用意されています。
| 関数名 | 読み方 | 役割 | 主な戻り値の範囲 |
|---|---|---|---|
| asin | アークサイン | sinの逆関数 | -π/2 〜 π/2 |
| acos | アークコサイン | cosの逆関数 | 0 〜 π |
| atan | アークタンジェント | tanの逆関数 | -π/2 〜 π/2 |
これらは、「三角関数の値」から「角度(ラジアン)を求める」ときに使います。
例えば、sinθ = 0.5である角度θを求めるにはasin(0.5)を使います。
また、2次元座標において、xとyから角度を求めたいときにはatan2という便利な関数もあります(こちらは2引数版のatanです)。
簡単な例を見てみます。
#define _USE_MATH_DEFINES // M_PIを有効にするための定義
#include <stdio.h>
#include <math.h>
int main(void) {
double v = 0.5;
double rad = asin(v); // sin(θ) = 0.5 となる θ (ラジアン)
double deg = rad * 180.0 / M_PI; // 度に変換
printf("asin(0.5) = %f (ラジアン)\n", rad);
printf("asin(0.5) = %f (度)\n", deg);
return 0;
}
asin(0.5) = 0.523599 (ラジアン)
asin(0.5) = 30.000000 (度)
このように逆三角関数を使うと、長さの比や座標から角度を求めることができます。
図形計算や物理シミュレーション、入力デバイスの向き検出など、さまざまな場面で利用されます。
図形計算やゲーム開発での三角関数の利用例
三角関数は、実際のプログラムの中でどのように使われるのでしょうか。
ここでは、2D平面上で、ある角度の方向に一定距離進んだ位置を計算するという、ゲーム開発でよくあるケースを例に説明します。
問題設定は次の通りです。
- プレイヤーの現在位置: (x, y)
- プレイヤーの向き(度): angle_deg
- 前に進む距離: dist
このとき、前進後の座標(x2, y2)は、三角関数を使って次のように求められます。
- x2 = x + dist * cos(rad)
- y2 = y + dist * sin(rad)
ここでradは、angle_degをラジアンに変換したものです。
#include <stdio.h>
#include <math.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
double deg2rad(double degree) {
return degree * M_PI / 180.0;
}
int main(void) {
// プレイヤーの初期位置
double x = 0.0;
double y = 0.0;
// 向き(度)と移動距離
double angle_deg = 45.0; // 右上方向を向いているとする
double dist = 10.0; // 10だけ前進
// 度をラジアンに変換
double angle_rad = deg2rad(angle_deg);
// 新しい位置を計算
double x2 = x + dist * cos(angle_rad);
double y2 = y + dist * sin(angle_rad);
printf("初期位置: (%.2f, %.2f)\n", x, y);
printf("向き: %.2f 度, 距離: %.2f\n", angle_deg, dist);
printf("移動後の位置: (%.2f, %.2f)\n", x2, y2);
return 0;
}
初期位置: (0.00, 0.00)
向き: 45.00 度, 距離: 10.00
移動後の位置: (7.07, 7.07)
この例では、45°方向へ10進んでいるので、x座標とy座標がほぼ同じ値(約7.07)になっています。
これは、cos(45°) = sin(45°) = √2/2 ≒ 0.7071であることに対応しています。
このように三角関数を使うことで、「向きと距離」から「新しい座標」を求めることができるため、以下のような場面で非常に役立ちます。
- キャラクターや弾丸の移動
- カメラの回転と視線方向の計算
- 図形の回転やスケーリング
- 波のアニメーション(上下に揺れる動きなど)
C言語でゲームやシミュレーションを作りたい場合、三角関数を自由自在に使いこなせるかどうかが、表現力や実装力に大きく影響してきます。
まとめ
本記事では、三角関数の基本から、C言語における具体的な計算方法までを解説しました。
sin・cos・tanは、直角三角形の辺の比や単位円上の座標を表す重要な関数であり、C言語ではmath.hをインクルードし、ラジアン単位で角度を扱うことがポイントです。
特に、度とラジアンの変換、πの扱い、tanの危険な角度には注意が必要です。
図形計算やゲーム開発など、実践的な場面で三角関数は必ず役に立ちますので、小さなサンプルから実際に手を動かして理解を深めてみてください。
