Почему это оценивается как ложное?

Я немного смущен и не могу объяснить это поведение:

Vector3 k = new Vector3(Mathf.NegativeInfinity, Mathf.NegativeInfinity,Mathf.NegativeInfinity);
Debug.Log(k==k); // evaluates to False

хотя

Debug.Log(Mathf.Mathf.NegativeInfinity == Mathf.Mathf.NegativeInfinity)
// evaluates to True as expected

Я использую Unity Version 5.3.5f1.

Ответ 1

От Unity документация, == возвращает "true для векторов, которые действительно близки к равным". Однако эта реализация создает проблемы, когда вектор инициализируется с отрицательной бесконечностью для x, y, z.

Посмотрим, как == определяется для Vector3:

public static bool operator == (Vector3 lhs, Vector3 rhs) {
    return Vector3.SqrMagnitude (lhs - rhs) < 9.999999E-11;
}

Прежде чем делать SqrMagnitude, он сначала выполнит lhs - rhs, поэтому давайте посмотрим, как определяется -:

public static Vector3 operator - (Vector3 a, Vector3 b) {
    return new Vector3 (a.x - b.x, a.y - b.y, a.z - b.z);
}

Это нормально для нормальных чисел, однако, поскольку a.x, b.x... и т.д. Mathf.NegativeInfinity, вычитание приведет к NaN. Теперь, когда он делает SqrMagnitude:

public float sqrMagnitude {
    get {
        return this.x * this.x + this.y * this.y + this.z * this.z;
    }
}

Это также вернет NaN.

В docs отметим следующее:

  • Если любой из операндов NaN, , результат является ложным для всех операторов, кроме! =, для которых результат равен true.

Поэтому, когда мы вернемся к этому коду:

return Vector3.SqrMagnitude (lhs - rhs) < 9.999999E-11;

Он упрощает return NaN < 9.999999E-11;, который вернет False, как указано в документах.


Кроме того, причина, по которой Debug.Log(Mathf.Mathf.NegativeInfinity == Mathf.Mathf.NegativeInfinity) ведет себя как ожидалось, документирована здесь.

  • Отрицательные и положительные нули считаются равными.
  • Отрицательная бесконечность считается меньше всех остальных значений , но равна другой отрицательной бесконечности.
  • Положительная бесконечность считается больше всех других значений, но равна другой положительной бесконечности.

Ответ 2

Оператор равенства может быть реализован или не может быть реализован. Это просто деталь реализации данного типа. Или это может быть также неправильно реализовано.

Даже если все свойства из данного класса могут сравниваться при сравнении двух ссылок, если == и != не перегружены или их реализация неверна, это может закончиться неожиданными результатами, такими как ваши.

Например:

public class A 
{
     public static operator bool ==(A left, A right) => false;
     public static operator bool !=(A left, A right) => false;
}

A a = new A();

bool equals = a == a; // false
bool notEquals = a != a // false

BTW:

bool referenceEquals = ReferenceEquals(a, a); // TRUE!

Ответ 3

Поскольку Mathf.NegativeInfinity не является фактическим числом. Это просто представление -Infinity. Согласно docs:

Представление отрицательной бесконечности (только для чтения).

Инициализация a Vector3 с помощью Mathf.NegativeInfinity, поскольку компоненты x, y, z не будут работать. Если вы попытаетесь напечатать этот вектор, вы получите (-Infinity, -Infinity, -Infinity) вместо любых чисел.

Запуск некоторых тестов показывает, что float.MaxValue - это максимальное значение, которое ведет себя соответственно в Vector3.

И как сказал Матиас в своем ответе о операторе =. Я считаю, что это верно для класса Vector3. Использование метода Equals также будет работать.

вот пример кода:

void Start () 
{
    Vector3 k = new Vector3(Mathf.NegativeInfinity, Mathf.NegativeInfinity,Mathf.NegativeInfinity);
    bool val = k==k;
    Debug.Log("Operator on Infinity Vector3: " + val);
    Debug.Log(k);
    Debug.Log("Equals Method on Infinity Vector3: " + k.Equals(k));

    val = (Mathf.NegativeInfinity == Mathf.NegativeInfinity);
    Debug.Log("Operator on float value: " + val);

    k = new Vector3(float.MaxValue, float.MaxValue,float.MaxValue);

    val = k==k ;
    Debug.Log("Operator on float.MaxValue: " + val);
    Debug.Log(k);
    Debug.Log("Equals Method on float.MaxValue: " + k.Equals(k));

}

Выше кода дает следующие результаты:

Оператор на бесконечности Vector3: False

(- Бесконечность, -Infinity, -Infinity)

Метод равенства по бесконечности Vector3: True

Оператор с поплавковым значением: True

Оператор на float.MaxValue: True

(340282300000000000000000000000000000000.0,  3402823000000000000000000000000000000000000, 3402823000000000000000000000000000000000000.0)

Метод равен: по float.MaxValue: True