Unity_Lesson

Mathf.Approximately とは?

Mathf.Approximately は、浮動小数点数(float型)の近似比較を行うUnityの関数です。

浮動小数点数の比較には誤差が伴うため、通常の == 演算子で正確に比較するのが難しい場合があります。Mathf.Approximately は、その誤差を考慮して「ほぼ等しい」と判断するために使われます。


シグネチャ

public static bool Approximately(float a, float b)

特徴


使用例

1. 通常の比較が失敗する例

float a = 0.1f + 0.2f; // 計算結果が厳密には 0.300000012f
float b = 0.3f;

if (a == b) {
    Debug.Log("等しい"); // 実行されない
} else {
    Debug.Log("等しくない");
}

浮動小数点数の計算誤差により、ab は「等しくない」と判断されます。

2. Mathf.Approximately を使用

float a = 0.1f + 0.2f;
float b = 0.3f;

if (Mathf.Approximately(a, b)) {
    Debug.Log("ほぼ等しい"); // 実行される
} else {
    Debug.Log("等しくない");
}

Mathf.Approximately を使用すると、ab が「ほぼ等しい」と判断されます。


内部実装(簡略化)

Mathf.Approximately の仕組みは、2つの値の差が小さな閾値(epsilon)以下かどうかを判定しています。

return Mathf.Abs(a - b) < Mathf.Epsilon;

実際のユースケース

1. 小数の比較

UIの移動などで小数点が絡む計算を行う場合、座標や距離が「ほぼ等しいか」を判定する際に使用します。

if (Mathf.Approximately(pos.y, 0f)) {
    pos.y = -center.y;
}

上記は、pos.y が0に非常に近い場合に、補正を適用する処理です。


注意点

bool AreAlmostEqual(float a, float b, float tolerance) {
    return Mathf.Abs(a - b) <= tolerance;
}

まとめ

Mathf.Approximately は、浮動小数点の比較を簡略化する便利な関数で、特に以下の場合に適しています:




浮動小数点数の誤差が起こる理由

浮動小数点数(floatdouble)の誤差は、コンピュータが数値を2進数で表現する仕組みと、有限のビット数による制約が原因です。


原因1: 数値を2進数で表現する制約

コンピュータは2進数(01)で数値を扱います。しかし、10進数で表現できるすべての数値が、2進数では有限の桁数で正確に表現できない場合があります。

具体例

10進数の 0.1 を2進数で表現するとどうなるか?

結果として、コンピュータ内部での 0.1厳密な0.1ではなく、少しズレた値 になります。


原因2: 有限のビット数による精度の限界

浮動小数点数は、IEEE 754標準に基づいて表現されます。この形式では、数値を以下のように分解します:

32ビットの float 型では、仮数部が23ビットしかないため、正確に表現できるのは 約7桁の10進数精度 です。


原因3: 加算・減算などの演算による累積誤差

浮動小数点数の演算では、結果に誤差がさらに加わる場合があります。

float a = 0.1f;
float b = 0.2f;
float c = a + b; // 結果は厳密な 0.3f ではない

誤差の影響が目立つ状況

  1. 繰り返し計算を行う場合
    • 小さな誤差が積み重なり、結果が大きくズレることがあります。
  2. 非常に小さい数値と非常に大きい数値を扱う場合
    • 精度が不均一になるため、丸め誤差が目立ちます。
  3. 数値の比較をする場合
    • 浮動小数点の比較で、想定外の「等しくない」判定が出ることがあります。

解決策や対策

  1. 整数型を使う
    • 誤差が許容できない場合、整数で計算を行い、小数点以下はスケールを使って調整する(例:金額計算で「小数」を使わない)。
    int a = 100; // 0.1 を 100倍として扱う
    int b = 200; // 0.2 を 100倍として扱う
    int c = a + b; // 結果は 300(0.3 を 100倍したもの)
    
  2. 許容範囲を設けて比較する
    • 誤差を考慮して、数値を「ほぼ等しい」と判定する。
    float tolerance = 0.0001f;
    if (Mathf.Abs(a - b) < tolerance) {
        Debug.Log("ほぼ等しい");
    }
    
  3. Mathf.Approximately を使う
    • Unityの標準関数を活用する(特にゲーム開発では便利)。
  4. double 型を使用する
    • float より精度が高い。ただし、必要以上に使うとメモリ使用量が増える。

まとめ

浮動小数点数の誤差は、2進数での表現の限界と有限ビット数による制約から生じます。この誤差は避けられませんが、許容範囲を設けたり整数型を使用することで多くの場面で対策可能です。

ゲーム開発では、Mathf.Approximately や許容誤差を使った比較が特に重要です!