[PHP]tan関数でタンジェント(正接)を計算する方法を徹底解説

PHP

三角関数というと「学校の数学で習ったけど実務では使わない」と思われがちですが、実際にはゲーム開発、グラフ描画、画像処理、物理シミュレーション、CAD系のツールなど、意外と多くの場面で登場します。その中でも tan() 関数は、傾きや角度の計算に欠かせない関数です。

この記事では tan() の基本仕様から、実践的な活用パターン、関連する三角関数との違い、そして見落としがちな落とし穴まで、コード例とともに詳しく解説します。

関数概要

項目内容
関数名tan()
読み方タンジェント、タン
分類数学関数
対応バージョンPHP 4以降(全バージョンで使用可能)
引数ラジアン単位の角度(float)
戻り値float(タンジェント値)
名前空間グローバル関数
関連拡張モジュール標準で組み込み(拡張モジュール不要)

構文

tan(float $angle): float

tan() は引数として ラジアン単位 の角度を1つ受け取り、そのタンジェント(正接)の値を浮動小数点数で返します。ここで最も重要なポイントは「度(degree)ではなくラジアンを渡す」という点です。学校で習った「90度」「45度」のような度数法の値をそのまま渡してしまうと、まったく意図しない結果になります。

基本的な使い方

<?php
echo tan(0) . PHP_EOL;
echo tan(M_PI / 4) . PHP_EOL; // 45度(π/4ラジアン)

実行結果:

0
0.99999999999999

M_PI はPHPに組み込まれている円周率の定数です。45度のタンジェントは数学的には正確に 1 になりますが、浮動小数点演算特有の誤差によって 0.99999999999999 のような値になる点に注意してください。

度数法からラジアンへの変換が必須

度数法の角度(degree)
        │
        │  deg2rad() で変換
        ▼
  ラジアン(radian)
        │
        │  tan() に渡す
        ▼
   タンジェント値(float)

PHPには度数法とラジアンを相互変換する便利な関数が用意されています。

<?php
$degree = 45;
$radian = deg2rad($degree);
echo tan($radian) . PHP_EOL;

実行結果:

0.99999999999999

deg2rad() を使わずに tan(45) と書いてしまうのは典型的な初心者のミスです。tan(45) は「45ラジアン」のタンジェントを計算してしまい、度数法の45度とは全く異なる値が返ってきます。

<?php
echo tan(45) . PHP_EOL;        // 45ラジアン(誤った使い方)
echo tan(deg2rad(45)) . PHP_EOL; // 45度(正しい使い方)

実行結果:

1.6197751905439
0.99999999999999

このように、結果が大きく異なることがわかります。

実践的なコード例

例1:度数法に対応したタンジェント計算クラス

<?php
class TrigonometryCalculator
{
    public function tanFromDegrees(float $degrees): float
    {
        return tan(deg2rad($degrees));
    }
}

$calc = new TrigonometryCalculator();

foreach ([0, 30, 45, 60] as $deg) {
    $result = $calc->tanFromDegrees($deg);
    printf("tan(%d度) = %.4f\n", $deg, $result);
}

実行結果:

tan(0度) = 0.0000
tan(30度) = 0.5774
tan(45度) = 1.0000
tan(60度) = 1.7321

度数法での入力を前提にラジアン変換をクラス内部に隠蔽しておくと、利用側でのミスを防ぎやすくなります。

例2:傾斜(スロープ)から角度を求める逆算

<?php
class SlopeAnalyzer
{
    /**
     * 水平距離と垂直距離から傾斜角度(度)を計算する
     */
    public function angleFromRise(float $rise, float $run): float
    {
        // tanの逆関数atanを使用(rise/runがtanθに相当)
        $radian = atan($rise / $run);
        return rad2deg($radian);
    }

    /**
     * 角度と水平距離から、必要な垂直距離(高さ)を計算する
     */
    public function riseFromAngle(float $degrees, float $run): float
    {
        return tan(deg2rad($degrees)) * $run;
    }
}

$slope = new SlopeAnalyzer();

$angle = $slope->angleFromRise(3, 10);
printf("傾斜角度: %.2f度\n", $angle);

$height = $slope->riseFromAngle(30, 10);
printf("30度のスロープで水平距離10mのときの高さ: %.2fm\n", $height);

実行結果:

傾斜角度: 16.70度
30度のスロープで水平距離10mのときの高さ: 5.77m

tan() は「角度→傾き」、その逆関数atan()は「傾き→角度」という対の関係にあり、建築やスロープ設計のような実務計算でよく組み合わせて使われます。

例3:2D座標から視線方向の角度を計算する(ゲーム開発向け)

<?php
class DirectionCalculator
{
    public function angleToTarget(float $fromX, float $fromY, float $toX, float $toY): float
    {
        $deltaX = $toX - $fromX;
        $deltaY = $toY - $fromY;

        // atan2を使うことで象限(向き)も正しく判定できる
        $radian = atan2($deltaY, $deltaX);
        return rad2deg($radian);
    }
}

$calc = new DirectionCalculator();

$angle = $calc->angleToTarget(0, 0, 10, 10);
printf("プレイヤーから敵への角度: %.2f度\n", $angle);

実行結果:

プレイヤーから敵への角度: 45.00度

補足:実際の角度計算では tan() ではなく atan2() を使うケースが多いです。tan() 自体は「角度から比率を求める」関数であり、「比率から角度を求めたい」場合は atan()atan2() を使うことに注意してください。

例4:周期的なアニメーションの揺れを表現する

<?php
class OscillationEffect
{
    public function valueAtFrame(int $frame, float $speed = 0.1): float
    {
        // tanは漸近線を持つため、振れ幅が急激に変化するエフェクトに使える
        $radian = $frame * $speed;
        return tan($radian);
    }
}

$effect = new OscillationEffect();

for ($frame = 0; $frame < 5; $frame++) {
    printf("フレーム%d: %.4f\n", $frame, $effect->valueAtFrame($frame));
}

実行結果:

フレーム0: 0.0000
フレーム1: 0.1003
フレーム2: 0.2027
フレーム3: 0.3093
フレーム4: 0.4228

注意:tan()sin()cos() と異なり、特定の角度(90度、270度など)で値が無限大に近づきます。アニメーションなど連続的な値の変化が必要な場面では、入力角度が漸近線付近に入らないよう範囲制限を入れることが重要です。

例5:建築・測量における高さの算出

<?php
class HeightSurveyor
{
    /**
     * 観測者からの距離と仰角(度)から対象物の高さを求める
     */
    public function estimateHeight(float $distance, float $elevationAngleDeg, float $observerHeight = 0): float
    {
        $radian = deg2rad($elevationAngleDeg);
        $height = tan($radian) * $distance;
        return $height + $observerHeight;
    }
}

$surveyor = new HeightSurveyor();

// 建物から50m離れた地点で、仰角35度、観測者の目の高さ1.6m
$height = $surveyor->estimateHeight(50, 35, 1.6);
printf("推定される建物の高さ: %.2fm\n", $height);

実行結果:

推定される建物の高さ: 36.61m

測量の分野では、距離と仰角から高さを求める際に tan() が頻繁に使われます。

例6:グリッド上での視野角・当たり判定の補助計算

<?php
class FieldOfViewHelper
{
    public function halfWidthAtDistance(float $distance, float $fovDegrees): float
    {
        $halfFovRadian = deg2rad($fovDegrees / 2);
        return tan($halfFovRadian) * $distance;
    }
}

$fov = new FieldOfViewHelper();

$halfWidth = $fov->halfWidthAtDistance(100, 60);
printf("距離100、視野角60度のときの半幅: %.2f\n", $halfWidth);
printf("視野の全幅: %.2f\n", $halfWidth * 2);

実行結果:

距離100、視野角60度のときの半幅: 57.74
視野の全幅: 115.46

3Dグラフィックスのカメラ視野角(FOV)の計算でも、tan() を使った距離と幅の変換がよく使われます。

例7:未定義の角度(漸近線)を安全に処理する

<?php
class SafeTangentCalculator
{
    public function calculate(float $degrees): string
    {
        // 90度、270度など、cosが0になる角度では未定義(無限大)になる
        $normalized = fmod($degrees, 180);

        if (abs($normalized - 90) < 0.0001) {
            return '未定義(垂直方向のため計算不可)';
        }

        $result = tan(deg2rad($degrees));
        return number_format($result, 4);
    }
}

$calc = new SafeTangentCalculator();

foreach ([45, 89.9999, 90, 135] as $deg) {
    echo "tan({$deg}度) = " . $calc->calculate($deg) . PHP_EOL;
}

実行結果:

tan(45度) = 1.0000
tan(89.9999度) = 572957.7951
tan(90度) = 未定義(垂直方向のため計算不可)
tan(135度) = -1.0000

90度に近づくほど値が急激に大きくなり、ちょうど90度では数学的に未定義(無限大)になります。実務でこのような角度を扱う場合は、事前にチェックを入れることでエラーや予期しない巨大な数値を防げます。

関連関数との比較

関数役割入力出力
tan()タンジェント(正接)を求めるラジアンfloat
sin()サイン(正弦)を求めるラジアンfloat
cos()コサイン(余弦)を求めるラジアンfloat
atan()tanの逆関数(アークタンジェント)比率ラジアン
atan2()象限を考慮したアークタンジェントy, x座標ラジアン
deg2rad()度数法をラジアンに変換度(degree)ラジアン
rad2deg()ラジアンを度数法に変換ラジアン度(degree)
hypot()直角三角形の斜辺の長さを求めるx, yfloat

tan() は単体で使うより、deg2rad()rad2deg()と組み合わせて使うのが基本パターンです。また「角度から比率」を求めるのがtan()で、その逆に「比率や座標から角度」を求めたいときはatan()atan2()を使う、という対応関係を意識すると関数選びに迷いにくくなります。

よくある落とし穴・注意点

  1. 度数法とラジアンの混同が最大の落とし穴 tan() の引数は必ずラジアンです。度数法の値をそのまま渡すミスは非常によくあるため、deg2rad() を通すことを徹底するか、tanFromDegrees() のようなラッパー関数を用意してチームで統一しておくと安全です。
  2. 90度・270度付近で値が無限大に近づく tan(90度) は数学的に未定義であり、コンピュータ上では非常に巨大な数値(オーバーフローに近い値)が返されることがあります。入力角度がこの「漸近線」付近に入る可能性がある場合は、事前にバリデーションを入れましょう。
  3. 浮動小数点演算特有の誤差 tan(deg2rad(45)) は数学的には正確に 1 になるはずですが、実際には 0.99999999999999 のような誤差を含む値が返ることがあります。等価比較(===)で厳密に判定するのではなく、abs($a - $b) < $epsilon のような許容誤差を使った比較を行いましょう。
  4. tan()atan()の使い分けミス 「角度を求めたいのにtan()を使ってしまう」というのは典型的な誤用です。求めたいものが「角度」なのか「比率(傾き)」なのかを最初に明確にし、関数を選ぶようにしましょう。
  5. 負の角度や360度を超える角度の扱い tan() 自体は負の値や360度を超える値もそのまま受け付けますが、周期性(180度ごとに同じ値が繰り返される)があるため、想定外の角度が渡されると意図しない結果になることがあります。必要に応じて fmod() で角度を正規化してから渡すと安全です。

まとめ

ポイント内容
役割ラジアン角度からタンジェント(正接)の値を計算する
引数ラジアン単位の角度(float)
戻り値float型のタンジェント値
周期性180度(πラジアン)ごとに同じ値が繰り返される
未定義になる角度90度、270度など(cosが0になる角度)
よく組み合わせる関数deg2rad(), rad2deg(), atan(), atan2()
主な用途傾斜・高さの計算、視野角計算、座標から角度の算出、アニメーション
注意点度数法との混同、漸近線付近の値、浮動小数点誤差

tan() は数学の授業のイメージから「実務では縁がない」と思われがちですが、測量、ゲーム開発、グラフィックス処理など、角度と長さ・比率を結びつける場面で意外と頻繁に登場します。deg2rad() とのセット使用を徹底し、漸近線付近の挙動に気をつけることで、安心して実務に組み込めるようになります。

タイトルとURLをコピーしました