【问题标题】:Why float.Epsilon and not zero?为什么 float.Epsilon 而不是零?
【发布时间】:2015-07-24 20:15:40
【问题描述】:

在下面的代码中,为什么要与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;
    }
}

【问题讨论】:

  • 因为float.Epsilon不是0。en.wikipedia.org/wiki/Machine_epsilon
  • 要么没必要要么不正确。如果作者试图避免舍入错误,那么float.Epsilon 通常是一个太小而无法使用的值。如果他们没有尝试避免舍入错误,那么他们正在做一些非常奇怪的事情(这也可能是不正确的)或不必要的。
  • 为什么这被否决了?对我来说似乎是一个合法的问题。
  • 我在看“Unity 2D Roguelike”教程,也想知道“float.Epsilon”,刚刚发现了同样的代码:)

标签: c# unity3d floating-accuracy


【解决方案1】:

实际上,在这里使用float.Epsilon 可能没有任何显着差异。 float.Epsilon 是大于零的最小可能float(大致为1.401298E-45),这意味着它是任意两个任意floats 之间的最小差异。由于浮点数学不精确,两个看似相等的数字之间的差异可能远大于float.Epsilon。例如:

float f1 = 1.0f / 3.0f;
float f = 1.0f;

(f1 * 3).Dump();  // 1
(f1 * 3 - f).Dump();  // 2.980232E-08

比较浮点数时,更好的做法是选择一个合理 值来确定两个浮点数是否“足够接近”以相等。这是一个上下文定义 - 例如对于距离,1mm“足够近”吗?也许在建造狗屋时,但不是电路板。你不会一直切割一块木头,直到它的长度在目标的1.401298E-45 米范围内。您将选择一个“足够接近”以称它们为相等的差异。

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

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

事实上,它记录在MSDN

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

【讨论】:

    【解决方案2】:

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

    43.65+61.11=104.75999999999999

    背后的原因是浮点数的实际保存方式。如果您不想深入研究,请记住浮点运算的一般限制,并且不要期望它们与数学中的值完全相同——包括,在本例中为 0。

    【讨论】: