Mathf_Approximately
Mathf.Approximately とは?
Mathf.Approximately は、浮動小数点数(float型)の近似比較を行うUnityの関数です。
浮動小数点数の比較には誤差が伴うため、通常の == 演算子で正確に比較するのが難しい場合があります。Mathf.Approximately は、その誤差を考慮して「ほぼ等しい」と判断するために使われます。
シグネチャ
public static bool Approximately(float a, float b)
- 引数
aとb:- 比較したい2つの浮動小数点数。
- 戻り値:
aとbが「ほぼ等しい」と判断されればtrueを返す。
特徴
- 浮動小数点数特有の誤差を許容:
- コンピュータ上では浮動小数点数の演算に微小な誤差が発生します。
- 例えば、
0.1 + 0.2を計算しても、結果が正確に0.3とはならない場合があります。
Mathf.Approximatelyはこの誤差を吸収し、「人間が見る限り等しい」と思える範囲で比較します。
使用例
1. 通常の比較が失敗する例
float a = 0.1f + 0.2f; // 計算結果が厳密には 0.300000012f
float b = 0.3f;
if (a == b) {
Debug.Log("等しい"); // 実行されない
} else {
Debug.Log("等しくない");
}
浮動小数点数の計算誤差により、a と b は「等しくない」と判断されます。
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 を使用すると、a と b が「ほぼ等しい」と判断されます。
内部実装(簡略化)
Mathf.Approximately の仕組みは、2つの値の差が小さな閾値(epsilon )以下かどうかを判定しています。
return Mathf.Abs(a - b) < Mathf.Epsilon;
Mathf.Abs:- 絶対値を求める関数。
Mathf.Epsilon:- 浮動小数点数で表現できる最小の正の値(非常に小さい値)。
- 具体的には
1.192092896e-07f(約0.0000001)。
実際のユースケース
1. 小数の比較
UIの移動などで小数点が絡む計算を行う場合、座標や距離が「ほぼ等しいか」を判定する際に使用します。
if (Mathf.Approximately(pos.y, 0f)) {
pos.y = -center.y;
}
上記は、pos.y が0に非常に近い場合に、補正を適用する処理です。
- 浮動小数点誤差で
pos.yが 0.00001 や -0.00001 のような値になる可能性がありますが、これを許容しています。
注意点
- 誤差が許容 される場面で使用する。
- 非常に大きな値や小さな値(例えば 1e10 や 1e-10)を比較すると、結果が不正確になる場合があります。その場合は自分で適切な閾値を設定した比較を行う必要があります。
bool AreAlmostEqual(float a, float b, float tolerance) {
return Mathf.Abs(a - b) <= tolerance;
}
まとめ
Mathf.Approximately は、浮動小数点の比較を簡略化する便利な関数で、特に以下の場合に適しています:
- 小数点以 下の誤差を気にしない場面。
- 「ほぼ等しい」かを判断したい場面。
浮動小数点数の誤差が起こる理由
浮動小数点数(float や double)の誤差は、コンピュータが数値を2進数で表現する仕組みと、有限のビット数による制約が原因です。
原因1: 数値を2進数で表現する制約
コンピュータは2進数(0 と 1)で数値を扱います。しかし、10進数で表現できるすべての数値が、2進数では有限の桁数で正確に表現できない場合があります。
具体例
10進数の 0.1 を2進数で表現するとどうなるか?
- 10進数の
0.1は、2進数では 0.00011001100110011...(無限に繰り返す)になります。 - これをコンピュータは有限のビット数で扱うため、途中で 切り捨て します。
結 果として、コンピュータ内部での 0.1 は 厳密な0.1ではなく、少しズレた値 になります。
原因2: 有限のビット数による精度の限界
浮動小数点数は、IEEE 754標準に基づいて表現されます。この形式では、数値を以下のように分解します:
- 符号部(1ビット):数値が正か負か。
- 指数部(8ビット or 11ビット):数値のスケール(10の何乗かに相当)。
- 仮数部(23ビット or 52ビット):実際の数値の細かい部分。
例
32ビットの float 型では、仮数部が23ビットしかないため、正確に表現できるのは 約7桁の10進数精度 です。
- それ以上の桁数は丸められるため、小さな誤差が生じます。
原因3: 加算・減算などの演算による累積誤差
浮動 小数点数の演算では、結果に誤差がさらに加わる場合があります。
例
float a = 0.1f;
float b = 0.2f;
float c = a + b; // 結果は厳密な 0.3f ではない
0.1や0.2はそれぞれ正確に表現されていないため、足し算の結果もズレます。