浮動小数点数の比較(丸め誤差に注意)
10進数を2進数に変換することにより、誤差が生じます。
プログラムで比較する場合、このことを考慮しないと同一値と判断されないことがあります。
テストコード
using System; using UnityEngine; public class FloatTest : MonoBehaviour { void Start() { Func<int, float, bool> Check; Debug.Log("floatの誤差"); Check = (i, f) => i == f * 10.0f; CompareCalc(Check); Debug.Log("floatの誤差(誤差の小ささで調整)"); Check = (i, f) => Mathf.Abs(i - f * 10.0f) < 0.001f; CompareCalc(Check); Debug.Log("floatの誤差(Equalsメソッドでチェック)"); Check = (i, f) => (f * 10.0f).Equals(i); CompareCalc(Check); Func<int, decimal, bool> CheckDeciaml; Debug.Log("floatの誤差(decimal型で比較)"); CheckDeciaml = (i, d) => i == d * 10.0m; CompareCalc(CheckDeciaml); Debug.Log("floatの誤差(decimal型で比較(Equalsメソッドでチェック))"); CheckDeciaml = (i, d) => (d * 10.0m).Equals(i); CompareCalc(CheckDeciaml); } /// <summary> /// 0から10までの整数を元に、float型で、10で割った結果を10倍して比較 /// </summary> /// <param name="compareFunc">Compare func.</param> private static void CompareCalc(Func<int, float, bool> compareFunc) { float data = 0.0f; for (int i = 0; i < 10; i++) { string compare; if (compareFunc(i, data)) { compare = "同じ"; } else { compare = "違う"; } Debug.Log(i + ":" + compare); data += 0.1f; } Debug.Log(""); } /// <summary> /// 0から10までの整数を元に、decimal型で、10で割った結果を10倍して比較 /// </summary> /// <param name="compareFunc">Compare func.</param> private static void CompareCalc(Func<int, decimal, bool> compareFunc) { decimal data = 0; for (int i = 0; i < 10; i++) { string compare; if (compareFunc(i, data)) { compare = "同じ"; } else { compare = "違う"; } Debug.Log(i + ":" + compare); data += 0.1m; } Debug.Log(""); } }
テストコード(LINQ版)
using System; using System.Linq; using UnityEngine; public class FloatTest : MonoBehaviour { void Start() { Func<int, float, bool> Check; Debug.Log("floatの誤差"); Check = (i, f) => i == f * 10.0f; CompareCalc(Check); Debug.Log("floatの誤差(誤差の小ささで調整)"); Check = (i, f) => Mathf.Abs(i - f * 10.0f) < 0.001f; CompareCalc(Check); Debug.Log("floatの誤差(Equalsメソッドでチェック)"); Check = (i, f) => (f * 10.0f).Equals(i); CompareCalc(Check); Func<int, decimal, bool> CheckDeciaml; Debug.Log("floatの誤差(decimal型で比較)"); CheckDeciaml = (i, d) => i == d * 10.0m; CompareCalc(CheckDeciaml); Debug.Log("floatの誤差(decimal型で比較(Equalsメソッドでチェック))"); CheckDeciaml = (i, d) => (d * 10.0m).Equals(i); CompareCalc(CheckDeciaml); } /// <summary> /// 0から10までの整数を元に、float型で、10で割った結果を10倍して比較 /// </summary> /// <param name="compareFunc">Compare func.</param> private static void CompareCalc(Func<int, float, bool> compareFunc) { Enumerable.Range(0, 10).ToList().ForEach(i => Debug.Log(compareFunc(i, (float)i / 10) ? $"{i} : 同じ" : $"{i} : 違う")); Debug.Log(""); } /// <summary> /// 0から10までの整数を元に、decimal型で、10で割った結果を10倍して比較 /// </summary> /// <param name="compareFunc">Compare func.</param> private static void CompareCalc(Func<int, decimal, bool> compareFunc) { Enumerable.Range(0, 10).ToList().ForEach(i => Debug.Log(compareFunc(i, (decimal)i / 10) ? $"{i} : 同じ" : $"{i} : 違う")); Debug.Log(""); } }
実行結果
floatの誤差 0 : 同じ 1 : 違う 2 : 違う 3 : 違う 4 : 違う 5 : 同じ 6 : 違う 7 : 違う 8 : 違う 9 : 違う floatの誤差(誤差の小ささで調整) 0 : 同じ 1 : 同じ 2 : 同じ 3 : 同じ 4 : 同じ 5 : 同じ 6 : 同じ 7 : 同じ 8 : 同じ 9 : 同じ floatの誤差(Equalsメソッドでチェック) 0 : 同じ 1 : 同じ 2 : 同じ 3 : 同じ 4 : 同じ 5 : 同じ 6 : 同じ 7 : 同じ 8 : 同じ 9 : 同じ floatの誤差(decimal型で比較) 0 : 同じ 1 : 同じ 2 : 同じ 3 : 同じ 4 : 同じ 5 : 同じ 6 : 同じ 7 : 同じ 8 : 同じ 9 : 同じ floatの誤差(decimal型で比較(Equalsメソッドでチェック)) 0 : 同じ 1 : 同じ 2 : 同じ 3 : 同じ 4 : 同じ 5 : 同じ 6 : 同じ 7 : 同じ 8 : 同じ 9 : 同じ
ディスカッション
コメント一覧
まだ、コメントがありません