单元测试 Mathf.Sine C#/Unity
Unit Test Mathf.Sine C# / Unity
我正在尝试写一个单元测试来检查是否有新的 vector3 returns (cos(angle), 0, sin(angle))。所以如果 pass angle = 0,它应该 returns (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));
}
谢谢!
使用Debug.Log
检查Mathf.Sin()/Cos()
return的实际值。 Vector3.ToString()
的默认精度是点 iirc 后的 5 位数字。要在调试日志中获得更高的精度,请使用
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()
returns -4.37139E-08
而不是 0
。原因是浮点精度限制。它打破了计算机科学中的很多东西。
从 Mathf.Sin()/Cos()
获得的角度为 0、90、120 的结果不会给你 0 和 1,而是给你像 4.371139E-08 这样的数字。这个值非常非常接近于零,但它不是零。因此,当您将此类结果与代码中的 new Vector
1、0 和 0 进行比较时,等式不成立。
虽然,Unity 中的 Vector3 == Vector3
操作已经应用了一些舍入,因此真正接近的值将被视为相等。与进行精确比较的 Vector3.Euals()
相反。
这是来自 Unity 源代码 repo 的 Vector3 == Vector3
操作的源代码: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度可能会return0.00001
,而==
操作会比较0.00001 * 0.00001 < kEpsilon * kEpsilon
,会return假,因为这些值实际上是一样的,所以运算结果
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
.
我正在尝试写一个单元测试来检查是否有新的 vector3 returns (cos(angle), 0, sin(angle))。所以如果 pass angle = 0,它应该 returns (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));
}
谢谢!
使用Debug.Log
检查Mathf.Sin()/Cos()
return的实际值。 Vector3.ToString()
的默认精度是点 iirc 后的 5 位数字。要在调试日志中获得更高的精度,请使用
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()
returns -4.37139E-08
而不是 0
。原因是浮点精度限制。它打破了计算机科学中的很多东西。
从 Mathf.Sin()/Cos()
获得的角度为 0、90、120 的结果不会给你 0 和 1,而是给你像 4.371139E-08 这样的数字。这个值非常非常接近于零,但它不是零。因此,当您将此类结果与代码中的 new Vector
1、0 和 0 进行比较时,等式不成立。
虽然,Unity 中的 Vector3 == Vector3
操作已经应用了一些舍入,因此真正接近的值将被视为相等。与进行精确比较的 Vector3.Euals()
相反。
这是来自 Unity 源代码 repo 的 Vector3 == Vector3
操作的源代码: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度可能会return0.00001
,而==
操作会比较0.00001 * 0.00001 < kEpsilon * kEpsilon
,会return假,因为这些值实际上是一样的,所以运算结果
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
.