mirror of
https://github.com/Ryujinx/Opentk.git
synced 2025-07-06 22:00:33 +00:00
Added new and improved floating-point equality tester.
This commit is contained in:
parent
6d0f3eb973
commit
fb71ebcffe
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace OpenTK
|
namespace OpenTK
|
||||||
|
@ -354,6 +355,73 @@ namespace OpenTK
|
||||||
return intDiff <= (1 << maxDeltaBits);
|
return intDiff <= (1 << maxDeltaBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Approximates double-precision floating point equality by an epsilon (maximum error) value.
|
||||||
|
/// This method is designed as a "fits-all" solution and attempts to handle as many cases as possible.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The first float.</param>
|
||||||
|
/// <param name="b">The second float.</param>
|
||||||
|
/// <param name="epsilon">The maximum error between the two.</param>
|
||||||
|
/// <returns><value>true</value> if the values are approximately equal within the error margin; otherwise, <value>false</value>.</returns>
|
||||||
|
[SuppressMessage("ReSharper", "CompareOfFloatsByEqualityOperator")]
|
||||||
|
public static bool ApproximatelyEqualEpsilon(double a, double b, double epsilon)
|
||||||
|
{
|
||||||
|
const double doubleNormal = (1L << 52) * double.Epsilon;
|
||||||
|
double absA = Math.Abs(a);
|
||||||
|
double absB = Math.Abs(b);
|
||||||
|
double diff = Math.Abs(a - b);
|
||||||
|
|
||||||
|
if (a == b)
|
||||||
|
{
|
||||||
|
// Shortcut, handles infinities
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == 0.0f || b == 0.0f || diff < doubleNormal)
|
||||||
|
{
|
||||||
|
// a or b is zero, or both are extremely close to it.
|
||||||
|
// relative error is less meaningful here
|
||||||
|
return diff < (epsilon * doubleNormal);
|
||||||
|
}
|
||||||
|
|
||||||
|
// use relative error
|
||||||
|
return diff / Math.Min((absA + absB), double.MaxValue) < epsilon;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Approximates single-precision floating point equality by an epsilon (maximum error) value.
|
||||||
|
/// This method is designed as a "fits-all" solution and attempts to handle as many cases as possible.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The first float.</param>
|
||||||
|
/// <param name="b">The second float.</param>
|
||||||
|
/// <param name="epsilon">The maximum error between the two.</param>
|
||||||
|
/// <returns><value>true</value> if the values are approximately equal within the error margin; otherwise, <value>false</value>.</returns>
|
||||||
|
[SuppressMessage("ReSharper", "CompareOfFloatsByEqualityOperator")]
|
||||||
|
public static bool ApproximatelyEqualEpsilon(float a, float b, float epsilon)
|
||||||
|
{
|
||||||
|
const float floatNormal = (1 << 23) * float.Epsilon;
|
||||||
|
float absA = Math.Abs(a);
|
||||||
|
float absB = Math.Abs(b);
|
||||||
|
float diff = Math.Abs(a - b);
|
||||||
|
|
||||||
|
if (a == b)
|
||||||
|
{
|
||||||
|
// Shortcut, handles infinities
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == 0.0f || b == 0.0f || diff < floatNormal)
|
||||||
|
{
|
||||||
|
// a or b is zero, or both are extremely close to it.
|
||||||
|
// relative error is less meaningful here
|
||||||
|
return diff < (epsilon * floatNormal);
|
||||||
|
}
|
||||||
|
|
||||||
|
// use relative error
|
||||||
|
float relativeError = diff / Math.Min((absA + absB), float.MaxValue);
|
||||||
|
return relativeError < epsilon;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
Loading…
Reference in a new issue