Является ли Mathf.Approximately (0.0f, float.Epsilon) == true своим правильным поведением? - PullRequest
4 голосов
/ 29 октября 2019

Я только что заметил, что следующий код возвращает true:

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

Я прочитал документацию Mathf.Approximately , и там говорится:

Приблизительно () сравнивает два числа с плавающей точкой и возвращает true, если они находятся в пределах небольшого значения (Epsilon) друг от друга.

И Mathf.Epsilon Документация гласит, что:

  • anyValue + Epsilon = anyValue
  • anyValue - Epsilon = anyValue
  • 0 + Epsilon = Epsilon
  • 0 - Epsilon = -Epsilon

В результате я запустил следующий код, ожидая, что он будет false, но он также возвращает true.

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 # )

Ответы [ 2 ]

5 голосов
/ 29 октября 2019

Вот декомпилированный код 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);
}
0 голосов
/ 29 октября 2019

Должно быть Mathf.Approximate(0.0f - 8.0f, float.Epsilon);. Поскольку у чисел с плавающей точкой может быть безумно маленькое число с плавающей запятой, вам нужно вычесть оба числа с плавающей точкой a и b, чтобы получить это маленькое число и сравнить его с float.epsilon.

[EDIT]

Было отмечено, что Mathf.Approximate не требует передачи эпсилона, поэтому должно быть достаточно Mathf.Approximate(float a, float b). Однако, если вам нужно установить собственный порог, вы можете использовать вышеупомянутый код.

...