1

我正在尝试写下一个单元测试来检查一个新的vector3是否返回(cos(角度),0,sin(角度))。因此,如果通过角度 = 0,它应该返回 (1,0,0)。

我知道它与 Episilon 有关,但我不知道如何制定它。

这是我的代码:

public Vector3 SetForceDirection(float angleInDegrees) 
    {
        float angleInRadians = angleInDegrees * Mathf.Deg2Rad;
        
        return new Vector3(Mathf.Cos(angleInRadians), 0, Mathf.Sin(angleInRadians));
    }

我的单元测试:

void SetforceDirection_Angle0_Return_1_0_0() 
    {
        CtrlHorizontal _ctrlHorizontal = new CtrlHorizontal();

        Vector3 result = _ctrlHorizontal.SetForceDirection(0);

        Assert.That(result == new Vector3(1, 0, 0));
    }

谢谢!

4

1 回答 1

1

用于Debug.Log检查Mathf.Sin()/Cos()实际返回的值。用于的默认精度Vector3.ToString()是点后 5 位,iirc。要在调试日志中获得更高的精度,请使用

Vector3 v = new Vector3(1.1234567891011, 0.00000001, 2.2222222222);
Debug.Log(v.ToString("F10"));

这应该在点之后打印 10 位数字的向量值。

那么,究竟发生了什么?
我们以 90 度角为例。结果Mathf.Cos()将是:

tmp1 = 90f * Mathf.Deg2Rad; // 1.570769
tmp2 = Mathf.Cos(tmp1); // -4.371139E-08

因此,Mathf.Cos()返回-4.37139E-08而不是0. 原因是浮点精度限制。它破坏了计算机科学中的很多东西。
从 0、90、120 等角度得到的结果Mathf.Sin()/Cos()不会给你 0 和 1,而是会给你像 4.371139E-08 这样的数字。这个值非常非常接近于零,但它不是零。因此,当您将这些结果与new Vector代码中的 1、0 和 0 进行比较时,等式会失败。
虽然,Vector3 == Vector3Unity 中的操作已经应用了一些舍入,因此彼此非常接近的值将被视为相等。而不是进行Vector3.Euals()精确比较。
以下是Vector3 == Vector3来自 Unity 源代码仓库的操作源代码:https://github.com/Unity-Technologies/UnityCsReference/blob/master/Runtime/Export/Math/Vector3.cs

// Returns true if the vectors are equal.
public static bool operator==(Vector3 lhs, Vector3 rhs)
{
    // Returns false in the presence of NaN values.
    float diff_x = lhs.x - rhs.x;
    float diff_y = lhs.y - rhs.y;
    float diff_z = lhs.z - rhs.z;
    float sqrmag = diff_x * diff_x + diff_y * diff_y + diff_z * diff_z;
    return sqrmag < kEpsilon * kEpsilon;
}

如您所见,它检查向量值之间的平方差是否小于kEpsilon * kEpsilon( kEpsilon = 0.00001,因此平方值为0.000000001)。
这里棘手的是Mathf.Cos()90 度可能会返回0.00001,并且==运算会比较0.00001 * 0.00001 < kEpsilon * kEpsilon它会返回 false,因为这些值实际上是相同的,所以运算的结果

Vector3 v1 = new Vector3(1, 0, 0); // your "checkout" vector
Vector3 v2 = new Vector3(1.00001, 0, 0); // the result of Mathf.Cos()/Sin() in your code
// in the Vector3 == Vector3 operation Unity does:
float sqrmag = 0.00001 * 0.00001 + 0 * 0 + 0 * 0;
return sqrmag < kEpsilon * kEpsilon;

0.000001 * 0.000001不小于kEpsilon * kEpsilon所以你得到向量不相同的结果。

因此,您需要以其他方式比较向量。作为一种选择,您可以尝试Mathf.Approximately(float a, float b)https://docs.unity3d.com/ScriptReference/Mathf.Approximately.html)分别比较向量的每个x, y, z值,而不是使用Vector3 == Vector3.

于 2021-04-06T11:08:41.370 回答