<PackageReference Include="NUnit" Version="3.9.0" />

Numerics

public static class Numerics
The Numerics class contains common operations on numeric values.
using NUnit.Framework.Internal; using System; namespace NUnit.Framework.Constraints { public static class Numerics { public static bool IsNumericType(object obj) { if (!IsFloatingPointNumeric(obj)) return IsFixedPointNumeric(obj); return true; } public static bool IsFloatingPointNumeric(object obj) { if (obj != null) { if (obj is double) return true; if (obj is float) return true; } return false; } public static bool IsFixedPointNumeric(object obj) { if (obj != null) { if (obj is byte) return true; if (obj is sbyte) return true; if (obj is decimal) return true; if (obj is int) return true; if (obj is uint) return true; if (obj is long) return true; if (obj is ulong) return true; if (obj is short) return true; if (obj is ushort) return true; if (obj is char) return true; } return false; } public static bool AreEqual(object expected, object actual, ref Tolerance tolerance) { if (expected is double || actual is double) return AreEqual(Convert.ToDouble(expected), Convert.ToDouble(actual), ref tolerance); if (expected is float || actual is float) return AreEqual(Convert.ToSingle(expected), Convert.ToSingle(actual), ref tolerance); if (tolerance.Mode == ToleranceMode.Ulps) throw new InvalidOperationException("Ulps may only be specified for floating point arguments"); if (expected is decimal || actual is decimal) return AreEqual(Convert.ToDecimal(expected), Convert.ToDecimal(actual), tolerance); if (expected is ulong || actual is ulong) return AreEqual(Convert.ToUInt64(expected), Convert.ToUInt64(actual), tolerance); if (expected is long || actual is long) return AreEqual(Convert.ToInt64(expected), Convert.ToInt64(actual), tolerance); if (expected is uint || actual is uint) return AreEqual(Convert.ToUInt32(expected), Convert.ToUInt32(actual), tolerance); return AreEqual(Convert.ToInt32(expected), Convert.ToInt32(actual), tolerance); } private static bool AreEqual(double expected, double actual, ref Tolerance tolerance) { if (double.IsNaN(expected) && double.IsNaN(actual)) return true; if (!double.IsInfinity(expected) && !double.IsNaN(expected) && !double.IsNaN(actual)) { if (tolerance.IsUnsetOrDefault) { Tolerance tolerance2 = TestExecutionContext.CurrentContext?.DefaultFloatingPointTolerance; if (tolerance2 != null && !tolerance2.IsUnsetOrDefault) tolerance = tolerance2; } switch (tolerance.Mode) { case ToleranceMode.Unset: return expected.Equals(actual); case ToleranceMode.Linear: return Math.Abs(expected - actual) <= Convert.ToDouble(tolerance.Amount); case ToleranceMode.Percent: if (expected == 0) return expected.Equals(actual); return Math.Abs((expected - actual) / expected) <= Convert.ToDouble(tolerance.Amount) / 100; case ToleranceMode.Ulps: return FloatingPointNumerics.AreAlmostEqualUlps(expected, actual, Convert.ToInt64(tolerance.Amount)); default: throw new ArgumentException("Unknown tolerance mode specified", "mode"); } } return expected.Equals(actual); } private static bool AreEqual(float expected, float actual, ref Tolerance tolerance) { if (float.IsNaN(expected) && float.IsNaN(actual)) return true; if (!float.IsInfinity(expected) && !float.IsNaN(expected) && !float.IsNaN(actual)) { if (tolerance.IsUnsetOrDefault) { Tolerance tolerance2 = TestExecutionContext.CurrentContext?.DefaultFloatingPointTolerance; if (tolerance2 != null && !tolerance2.IsUnsetOrDefault) tolerance = tolerance2; } switch (tolerance.Mode) { case ToleranceMode.Unset: return expected.Equals(actual); case ToleranceMode.Linear: return (double)Math.Abs(expected - actual) <= Convert.ToDouble(tolerance.Amount); case ToleranceMode.Percent: if (expected == 0) return expected.Equals(actual); return Math.Abs((expected - actual) / expected) <= Convert.ToSingle(tolerance.Amount) / 100; case ToleranceMode.Ulps: return FloatingPointNumerics.AreAlmostEqualUlps(expected, actual, Convert.ToInt32(tolerance.Amount)); default: throw new ArgumentException("Unknown tolerance mode specified", "mode"); } } return expected.Equals(actual); } private static bool AreEqual(decimal expected, decimal actual, Tolerance tolerance) { switch (tolerance.Mode) { case ToleranceMode.Unset: return expected.Equals(actual); case ToleranceMode.Linear: { decimal num = Convert.ToDecimal(tolerance.Amount); if (num > decimal.Zero) return Math.Abs(expected - actual) <= num; return expected.Equals(actual); } case ToleranceMode.Percent: if (expected == decimal.Zero) return expected.Equals(actual); return Math.Abs((double)(expected - actual) / (double)expected) <= Convert.ToDouble(tolerance.Amount) / 100; default: throw new ArgumentException("Unknown tolerance mode specified", "mode"); } } private static bool AreEqual(ulong expected, ulong actual, Tolerance tolerance) { switch (tolerance.Mode) { case ToleranceMode.Unset: return expected.Equals(actual); case ToleranceMode.Linear: { ulong num = Convert.ToUInt64(tolerance.Amount); if (num != 0) return ((expected >= actual) ? (expected - actual) : (actual - expected)) <= num; return expected.Equals(actual); } case ToleranceMode.Percent: if (expected == 0) return expected.Equals(actual); return Math.Abs((double)(Math.Max(expected, actual) - Math.Min(expected, actual)) / (double)expected) <= Convert.ToDouble(tolerance.Amount) / 100; default: throw new ArgumentException("Unknown tolerance mode specified", "mode"); } } private static bool AreEqual(long expected, long actual, Tolerance tolerance) { switch (tolerance.Mode) { case ToleranceMode.Unset: return expected.Equals(actual); case ToleranceMode.Linear: { long num = Convert.ToInt64(tolerance.Amount); if (num > 0) return Math.Abs(expected - actual) <= num; return expected.Equals(actual); } case ToleranceMode.Percent: if (expected == 0) return expected.Equals(actual); return Math.Abs((double)(expected - actual) / (double)expected) <= Convert.ToDouble(tolerance.Amount) / 100; default: throw new ArgumentException("Unknown tolerance mode specified", "mode"); } } private static bool AreEqual(uint expected, uint actual, Tolerance tolerance) { switch (tolerance.Mode) { case ToleranceMode.Unset: return expected.Equals(actual); case ToleranceMode.Linear: { uint num = Convert.ToUInt32(tolerance.Amount); if (num != 0) return ((expected >= actual) ? (expected - actual) : (actual - expected)) <= num; return expected.Equals(actual); } case ToleranceMode.Percent: if (expected == 0) return expected.Equals(actual); return Math.Abs((double)(Math.Max(expected, actual) - Math.Min(expected, actual)) / (double)expected) <= Convert.ToDouble(tolerance.Amount) / 100; default: throw new ArgumentException("Unknown tolerance mode specified", "mode"); } } private static bool AreEqual(int expected, int actual, Tolerance tolerance) { switch (tolerance.Mode) { case ToleranceMode.Unset: return expected.Equals(actual); case ToleranceMode.Linear: { int num = Convert.ToInt32(tolerance.Amount); if (num > 0) return Math.Abs(expected - actual) <= num; return expected.Equals(actual); } case ToleranceMode.Percent: if (expected == 0) return expected.Equals(actual); return Math.Abs((double)(expected - actual) / (double)expected) <= Convert.ToDouble(tolerance.Amount) / 100; default: throw new ArgumentException("Unknown tolerance mode specified", "mode"); } } public static int Compare(object expected, object actual) { if (!IsNumericType(expected) || !IsNumericType(actual)) throw new ArgumentException("Both arguments must be numeric"); if (IsFloatingPointNumeric(expected) || IsFloatingPointNumeric(actual)) return Convert.ToDouble(expected).CompareTo(Convert.ToDouble(actual)); if (expected is decimal || actual is decimal) return Convert.ToDecimal(expected).CompareTo(Convert.ToDecimal(actual)); if (expected is ulong || actual is ulong) return Convert.ToUInt64(expected).CompareTo(Convert.ToUInt64(actual)); if (expected is long || actual is long) return Convert.ToInt64(expected).CompareTo(Convert.ToInt64(actual)); if (expected is uint || actual is uint) return Convert.ToUInt32(expected).CompareTo(Convert.ToUInt32(actual)); return Convert.ToInt32(expected).CompareTo(Convert.ToInt32(actual)); } } }