为什么float.Epsilon而不是零?

时间:2015-05-13 13:37:34

标签: c# unity3d floating-accuracy

在下面的代码中,为什么与float.Epsilon进行比较而不是0?

// 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;
    }
}

2 个答案:

答案 0 :(得分:33)

实际上,使用float.Epsilon可能不会在这里产生任何重大差异。 float.Epsilon是可能最小的float大于零(大约1.401298E-45),意味着它是任意两个{{1}之间的最小差异}秒。由于浮点数学不精确,两个看似相等的数字之间的差异可能比float 更大。例如:

float.Epsilon

比较浮点数时,更好的做法是选择合理的值来确定两个浮点数是否“足够接近”相等。这是一个语境定义 - 例如对于距离,是1mm“足够接近”?也许在建造狗屋时,而不是电路板。你不会继续切割一块木头,直到它的长度在目标的float f1 = 1.0f / 3.0f; float f = 1.0f; (f1 * 3).Dump(); // 1 (f1 * 3 - f).Dump(); // 2.980232E-08 米之内。你将选择一个“足够接近”的差异来称呼它们。

对于精灵运动(我假设这是在样本中所做的) - 也许更合理的“epsilon”是可以在高分辨率监视器上表示的最小距离(或者至少会被注意到通过人眼)。

所有这一点1.401298E-45在这里可能同样合理,因为0和sqrRemainingDistance > 0之间没有其他数字可以是数字,但更好选择可能比float.Epsilon大一些,以确定何时停止循环。为了获得“合理”的结果,该程序可能会循环更多的东西。

事实上,它记录在MSDN

  

如果创建一个自定义算法来确定是否可以认为两个浮点数相等,则必须使用大于Epsilon常数的值来确定可接受的两个值的绝对差值,以使两个值相等。 (通常,差异幅度比Epsilon大很多倍。)

答案 1 :(得分:2)

因为floating point math is not precise。我链接的文章冗长而详细,让我用一个简单的例子来解释:

  

43.65 + 61.11 = 104.75999999999999

背后的原因是如何实际保存浮点数。如果你不想深入研究这个问题,请记住浮点运算的一般局限性,并且根据数学不要指望它们应该是它们应该是什么 - 包括,在这种情况下, 0