web-dev-qa-db-ja.com

なぜfloat.Epsilonでゼロではないのですか?

次のコードでは、なぜ0ではなくfloat.Epsilonとの比較があるのですか?

// Coroutine to move elements
protected IEnumerator SmoothMovement (Vector3 end)
{
    // Distance computation
    float sqrRemainingDistance = (transform.position - end).sqrMagnitude;

    while(sqrRemainingDistance > float.Epsilon)
    {
        Vector3 newPostion = Vector3.MoveTowards(
            rb2D.position, end, inverseMoveTime * Time.deltaTime
        );
        rb2D.MovePosition (newPostion);
        sqrRemainingDistance = (transform.position - end).sqrMagnitude;
        yield return null;
    }
}
32
Olivier Pons

実際、float.Epsilonを使用しても、ここで大きな違いは生じません。 float.Epsilonはゼロよりも大きい最小のfloat(ほぼ1.401298E-45)です。これはnotが、任意の2つのfloats。浮動小数点演算は不正確であるため、見かけ上等しい2つの数値の差は、SOMECODE] _よりも--- [はるかに大きいになります。例えば:

float.Epsilon

フロートを比較するときは、2つのフロートが等しくなるのに「十分に近い」かどうかを判断するためにreasonable値を選択することをお勧めします。それは文脈上の定義です-例えば距離については、1mmで「十分に近い」ですか?犬小屋を建てるときかもしれませんが、回路基板ではありません。木材の長さがターゲットのfloat f1 = 1.0f / 3.0f; float f = 1.0f; (f1 * 3).Dump(); // 1 (f1 * 3 - f).Dump(); // 2.980232E-08 メートル以内になるまで、木材を切断し続けることはできません。それらを同等と呼ぶには「十分に近い」違いを選択します。

スプライトの動き(これはサンプルで行われていると仮定しています)-より合理的な「イプシロン」は、高解像度モニターで表現できる最小の距離です(少なくとも、人間が気づくはずです)眼)。

1.401298E-45は、0とsqrRemainingDistance > 0の間に他の数字はないので、ここではfloat.Epsilonと同じくらい合理的かもしれませんが、betterの選択肢はループを停止するタイミングを決定するEpsilonよりもはるかに大きい数値。プログラムは、「合理的な」結果を得るために必要以上にループしている可能性があります。

実際、それは [〜#〜] msdn [〜#〜] で文書化されています:

2つの浮動小数点数が等しいと見なされるかどうかを決定するカスタムアルゴリズムを作成する場合、イプシロン定数より大きい値を使用して、2つの値が等しいと見なされる許容差の絶対マージンを確立する必要があります。 (通常、その差のマージンはEpsilonよりも何倍も大きいです。)

37
D Stanley

浮動小数点演算は正確ではない であるため。リンクした記事は長く詳細ですので、簡単な例を説明します。

43.65 + 61.11 = 104.75999999999999

背後にある理由は、浮動小数点数が実際に保存される方法です。これに飛び込みたくない場合は、浮動小数点演算の一般的な制限を念頭に置いてください。また、それらが数学に基づいた正確なものであると期待しないでください。この場合は0です。

2
Max Yankov