private static void TestBinaryOperationFloatApproximate(float a, float b, float expected, BinaryOperationType op) { BinaryOperation func = binaryOperations[(int)op]; sfloat result = func((sfloat)a, (sfloat)b); if (float.IsNaN(expected) && result.IsNaN()) { // special case, NaN-s cannot be compared return; } if (float.IsInfinity(expected) && result.IsInfinity() && MathF.Sign(expected) == result.Sign()) { // both are the same infinities return; } float allowedError = MathF.Max(1e-6f * MathF.Pow(2.0f, MathF.Log2(MathF.Abs(expected) + 1.0f)), 1e-6f); float difference = MathF.Abs((float)result - expected); bool isOk = difference < allowedError; Debug.Assert(isOk); }
private static void TestUnaryOperationFloatApproximate(float x, float expected, UnaryOperationType op, float allowedErrorMultiplier = 1.0f) { UnaryOperation func = unaryOperations[(int)op]; sfloat result = func((sfloat)x); if (float.IsNaN(expected) && result.IsNaN()) { // special case, NaN-s cannot be compared return; } if (float.IsInfinity(expected) && result.IsInfinity() && MathF.Sign(expected) == result.Sign()) { // both are the same infinities return; } float allowedError = MathF.Max(1e-6f * allowedErrorMultiplier * MathF.Pow(2.0f, MathF.Log2(MathF.Abs(expected) + 1.0f)), 1e-6f); float difference = MathF.Abs((float)result - expected); bool isOk = difference <= allowedError; if (!isOk && (op == UnaryOperationType.Round || op == UnaryOperationType.Floor || op == UnaryOperationType.Ceiling)) { // Because of the loss of precision that can result from representing decimal values // as floating-point numbers or performing arithmetic operations on floating-point values, // in some cases the Round method may not appear to round midpoint values to the nearest even integer. // https://docs.microsoft.com/en-us/dotnet/api/system.math.round if (MathF.Abs(x % 1.0f) - 0.5f < 0.01f) { // x is near a midpoint, it's possible that rounding happened in a different direction isOk = MathF.Abs((float)result - expected) <= 1.0f; } } Debug.Assert(isOk); }