是 Mathf.Approximately(0.0f, float.Epsilon) == true 它的正确行为?

Is Mathf.Approximately(0.0f, float.Epsilon) == true its correct behavior?

提问人:ianmandarini 提问时间:10/29/2019 更新时间:10/29/2019 访问量:2344

问:

我刚刚注意到以下代码返回 true:

Mathf.Approximately(0.0f, float.Epsilon); // true

我已经阅读了 Mathf.Approximately 文档,它指出:

Approximately() 比较两个浮点数,如果它们在彼此之间的小值 (Epsilon) 内,则返回 true。

Mathf.Epsilon 文档指出:

  • anyValue + Epsilon = anyValue
  • anyValue - Epsilon = anyValue
  • 0 + 厄普西隆 = 厄普西隆
  • 0 - 厄普西隆 = -厄普西隆

结果,我运行了以下代码,期望它是 ,但它也返回 .falsetrue

Mathf.Approximately(0.0f, 2.0f * float.Epsilon); // true

顺便一提:

Mathf.Approximately(0.0f, 2.0f * float.Epsilon); // true
Mathf.Approximately(0.0f, 3.0f * float.Epsilon); // true
Mathf.Approximately(0.0f, 4.0f * float.Epsilon); // true
Mathf.Approximately(0.0f, 5.0f * float.Epsilon); // true
Mathf.Approximately(0.0f, 6.0f * float.Epsilon); // true
Mathf.Approximately(0.0f, 7.0f * float.Epsilon); // true

Mathf.Approximately(0.0f, 8.0f * float.Epsilon); // false
Mathf.Approximately(0.0f, 9.0f * float.Epsilon); // false

问:基于这些证据,我可以肯定地说 Mathf.Approximately 没有根据其文档*正确实现吗?

(* 因此,我应该转向不同的解决方案,例如 C# 的浮点比较函数中的解决方案)

C# unity-game-engine 浮点 精度 float-accuracy

评论

1赞 Immersive 10/29/2019
我可以确认,所以看起来文档确实有点......松散地描述其算法(仅;)“近似”。但是你真的需要近似值那么精确吗?Mathf.Epsilon == float.Epsilon
1赞 ianmandarini 10/29/2019
当我实现一个函数 public static bool IsInRangeOf(this float thisFloat, float otherFloat, float range) 时,我遇到了这个问题,该函数回答 thisFloat 是否在区间内(otherFloat - range, otherFloat + range)。我幼稚的实现是将 Mathf.Abs(otherFloat - thisFloat) < 范围返回,但在 [TestCase(0.91f, 1.0f - 0.09f, float.Epsilon, ExpectedResult = true)]。最终,我遇到了这个函数,这导致我在 Stack Overflow 中创建了这个问题。Mathf.Approximately
0赞 ianmandarini 10/29/2019
因此,我认为这更像是定义已接受测试用例的行为的问题,而不是需要精度。例如,我可以定义一个约束,即范围应至少为两个浮点数之间差值的 10%,如果输入与该约束不匹配,则抛出 ArgumentOutOfRangeException。甚至,接受函数会受到浮点误差的影响,特别是当浮点数彼此非常接近时。我想从这里得到的只是是否有人有任何我可能没有的信息,以便我可以做出明智的决定。Mathf.Approximately
0赞 ianmandarini 10/29/2019
@Immersive我认为一个答案是,也说明文档有点松散/阈值是无文档的,然后问修辞问题是否真的需要精度(也许补充说浮点运算错误容易出错,并且应该始终检查错误在很大程度上取决于浮点数可以假设的值域)是一个很好的答案。你能把它作为一个答案,以便我们从评论中得到这个,我可以接受它吗?Mathf.Epsilon == float.Epsilon
1赞 Menyus 10/29/2019
你不是第一个对这个 stackoverflow.com/questions/28471464/ 感到困惑的人......

答:

-1赞 Kyle Kristopher Garcia 10/29/2019 #1

它应该是.由于浮点数可以有一个非常小的浮点数,因此您需要减去浮点数 a 和 b 才能得到这个小数并将其与 float.epsilon 进行比较。Mathf.Approximate(0.0f - 8.0f, float.Epsilon);

[编辑]

有人指出,Mathf.Approximate 不需要传递 epsilon,所以应该足够了。但是,如果需要设置自己的阈值,则可以使用上述代码。Mathf.Approximate(float a, float b)

评论

0赞 Immersive 10/29/2019
没有。 用于比较两个参数之间接近于零的差值,使用(隐藏/硬编码)阈值 。这与数字的“负数”无关。Mathf.Approximately()Mathf.Epsilon
0赞 Kyle Kristopher Garcia 10/29/2019
我的措辞一定有问题。我没有提到数字必须是负数或“负数”数字应该是负数。我只是解释说,他应该得到两个浮动变量之间的差值,以便得到一个值,他需要将其进行比较。Mathf.Epsilon
1赞 Immersive 10/29/2019
啊。不好意思。是的。近似值是差值的比较,但函数的签名是 ,比较的阈值是硬编码的。因此,无需从 b 中减去 a,只需使用 a 和 b 作为参数即可。(compareLeft, compareRight)
0赞 Kyle Kristopher Garcia 10/29/2019
我刚刚遇到了Mathf.Approximately,我认为它需要一个epsilon。我使用我自己的近似函数,这就是为什么我认为 Mathf.Approximate 需要传递一个 epsilon。我会纠正我的答案。
9赞 Menyus 10/29/2019 #2

这是 Unity 的反编译代码,您可以在末尾看到^^,因此确实是一个记录不佳的方法。public static bool Mathf.Approximately(float a, float b);* 8.0f

/// <summary>
/// <para>Compares two floating point values if they are similar.</para>
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
public static bool Approximately(float a, float b)
{
   return (double) Mathf.Abs(b - a) < (double) Mathf.Max(1E-06f * Mathf.Max(Mathf.Abs(a),
       Mathf.Abs(b)), Mathf.Epsilon * 8.0f);
}