Регулировать поплавок расхождение в Unity3D


Я знаю, что есть тысячи сообщений и вопросов по теме Float Discrepancy. И это не совсем вопрос, но обсуждение его.

Посидев несколько раз перед той же проблемой, я создал следующий класс, чтобы справиться с этим раз и для всех наших проектов. Прямое сравнение стоимости из книги Искусство программирования Дональд Э. кнут. Я просто поменял на unitys функциональность Mathf.

Так каков ваш взгляд на проблему? Что-то добавить, что-то не так?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public static class FloatDiscrepancy {
  public static float Accuracy = 0.00001f;

  public static float SqrAccuracy {
    get {
     return Accuracy * Accuracy;
    }
    private set { }
  }

  public static bool V4Equal(Vector4 a, Vector4 b){
    return Vector4.SqrMagnitude(a - b) < SqrAccuracy;
  }

  public static bool V3Equal(Vector3 a, Vector3 b){
    return Vector3.SqrMagnitude(a - b) < SqrAccuracy;
  }

  public static bool V2Equal (Vector2 a, Vector2 b){
    return Vector2.SqrMagnitude (a - b) < SqrAccuracy;
  }

  public static bool QuaternionEqual(Quaternion a, Quaternion b){
    return Quaternion.Angle (a, b) < Accuracy;
  }

  //Took the following from literature: The Art of Computer Programming by Donald E. Knuth
  public static bool approximatelyEqual(float a, float b){
    return Mathf.Abs(a - b) <= ( (Mathf.Abs(a) < Mathf.Abs(b) ? Mathf.Abs(b) : Mathf.Abs(a)) * Accuracy);
  }

  public static bool essentiallyEqual(float a, float b){
    return Mathf.Abs(a - b) <= ( (Mathf.Abs(a) > Mathf.Abs(b) ? Mathf.Abs(b) : Mathf.Abs(a)) * Accuracy);
  }

  public static bool definitelyGreaterThan(float a, float b){
    return (a - b) > ( (Mathf.Abs(a) < Mathf.Abs(b) ? Mathf.Abs(b) : Mathf.Abs(a)) * Accuracy);
  }

  public static bool definitelyLessThan(float a, float b){
    return (b - a) > ( (Mathf.Abs(a) < Mathf.Abs(b) ? Mathf.Abs(b) : Mathf.Abs(a)) * Accuracy);
  }
}


Комментарии
1 ответ

Я не могу понять, в какой ситуации вы будете использовать approximatelyEqual() и в который essentiallyEqual(). и какая разница действительно должна быть.

Я сделал несколько тестов и в целом, это, кажется, работает. Я, правда найти ниже странное поведение:

Испытания с этими двумя значениями:

    float a = 1.0f; 
float b = 1.0f + 1e-6f;

Console.WriteLine($"a: {a:F15}");
Console.WriteLine($"b: {b:F15}");
Console.WriteLine($"a - b: {a - b:F15}");
Console.WriteLine($"b - a: {b - a:F15}");
Console.WriteLine();

Console.WriteLine($"approximatelyEqual: {approximatelyEqual(a, b)}");
Console.WriteLine($"essentiallyEqual: {essentiallyEqual(a, b)}");
Console.WriteLine($"definitelyGreaterThan: {definitelyGreaterThan(a, b)}");
Console.WriteLine($"definitelyLessThan: {definitelyLessThan(a, b)}");
Console.WriteLine();
Console.WriteLine($"HEquals: {HEquals(a, b)}");
Console.WriteLine($"HGreaterThan: {HGreaterThan(a, b)}");
Console.WriteLine($"HLessThan: {HLessThan(a, b)}");

Я получаю ожидаемый результат:

a: 1.000000000000000
b: 1.000001000000000
a - b: -0.000000953674300
b - a: 0.000000953674300

approximatelyEqual: True
essentiallyEqual: True
definitelyGreaterThan: False
definitelyLessThan: False

HEquals: True
HGreaterThan: False
HLessThan: False

Но если бы я попробовать это:

    float a = 0.0f; 
float b = 1e-6f;

Я получаю это:

a: 0.000000000000000
b: 0.000001000000000
a - b: -0.000001000000000
b - a: 0.000001000000000

approximatelyEqual: False
essentiallyEqual: False
definitelyGreaterThan: False
definitelyLessThan: True

HEquals: True
HGreaterThan: False
HLessThan: False

Но я ожидал бы тот же результат?


Н-функции-мое собственное наивных реализациях:

public static bool HEquals(float a, float b)
{
return Math.Abs(a - b) < Accuracy;
}

public static bool HGreaterThan(float a, float b)
{
return a - b >= Accuracy;
}

public static bool HLessThan(float a, float b)
{
return a - b <= -Accuracy;
}


Отказ от ответственности: я не использую Unity3ds Mathf.Abs() но System.Math.Abs()

2
ответ дан 5 апреля 2018 в 06:04 Источник Поделиться