I am trying to write down a unit test to check if a new vector3 returns (cos(angle), 0, sin(angle)). So if pass angle = 0, it should returns (1,0,0).
I know it is something related to the Episilon, but I don't know how to formulate it.
Here is my code:
public Vector3 SetForceDirection(float angleInDegrees)
{
float angleInRadians = angleInDegrees * Mathf.Deg2Rad;
return new Vector3(Mathf.Cos(angleInRadians), 0, Mathf.Sin(angleInRadians));
}
And my unit test:
void SetforceDirection_Angle0_Return_1_0_0()
{
CtrlHorizontal _ctrlHorizontal = new CtrlHorizontal();
Vector3 result = _ctrlHorizontal.SetForceDirection(0);
Assert.That(result == new Vector3(1, 0, 0));
}
Thanks!
Use
Debug.Logto check what valuesMathf.Sin()/Cos()return actually. The default precision used forVector3.ToString()is 5 digits after the dot, iirc. To get higher precision in the debug logs, useThis should print the vector values with 10 digits after the dot.
So, what's actually happening?
Let's take for example the angle 90 degrees. The result of
Mathf.Cos()will be:So,
Mathf.Cos()returns-4.37139E-08rather than0. The reason is floating points precision limit. It breaks a lot of things in computer science.The results you get from
Mathf.Sin()/Cos()with angles like 0, 90, 120 won't give you 0's and 1's, instead they will give you numbers like 4.371139E-08. This value is very very very close to zero but it's not a zero. So, when you compare such results to thenew Vector1, 0 and 0 in your code the equation fails.Although, the
Vector3 == Vector3operation in Unity already should apply some rounding so the values that are really close to each other will be treated as equal. As opposed toVector3.Euals()which does the exact comparison.Here is the source code of the
Vector3 == Vector3operation from Unity's source code repo: https://github.com/Unity-Technologies/UnityCsReference/blob/master/Runtime/Export/Math/Vector3.csAs you can see, it checks if the squared difference between the vectors values is less than
kEpsilon * kEpsilon(kEpsilon = 0.00001, so the squared value is0.000000001).The tricky thing here is
Mathf.Cos()of 90 degrees might return0.00001, and the==operation will compare0.00001 * 0.00001 < kEpsilon * kEpsilonand it will return false, because these values are the same actually, so the result of the operation0.000001 * 0.000001is not less thankEpsilon * kEpsilonso you get the result where the vectors are not the same.So, you'll need to compare the vectors in some other way. As an option, you could try
Mathf.Approximately(float a, float b)( https://docs.unity3d.com/ScriptReference/Mathf.Approximately.html ) to compare eachx, y, zvalues of the vectors separately instead of usingVector3 == Vector3.