// // Math.NET Numerics, part of the Math.NET Project // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // // Copyright (c) 2009-2013 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Collections.Generic; using IStation.Numerics.LinearAlgebra; using Complex = System.Numerics.Complex; namespace IStation.Numerics { // TODO PERF: Cache/Precompute 10^x terms public static partial class Precision { /// /// Compares two doubles and determines if they are equal /// within the specified maximum absolute error. /// /// The norm of the first value (can be negative). /// The norm of the second value (can be negative). /// The norm of the difference of the two values (can be negative). /// The absolute accuracy required for being almost equal. /// True if both doubles are almost equal up to the specified maximum absolute error, false otherwise. public static bool AlmostEqualNorm(this double a, double b, double diff, double maximumAbsoluteError) { // If A or B are infinity (positive or negative) then // only return true if they are exactly equal to each other - // that is, if they are both infinities of the same sign. if (double.IsInfinity(a) || double.IsInfinity(b)) { return a == b; } // If A or B are a NAN, return false. NANs are equal to nothing, // not even themselves. if (double.IsNaN(a) || double.IsNaN(b)) { return false; } return Math.Abs(diff) < maximumAbsoluteError; } /// /// Compares two doubles and determines if they are equal /// within the specified maximum absolute error. /// /// The first value. /// The second value. /// The absolute accuracy required for being almost equal. /// True if both doubles are almost equal up to the specified maximum absolute error, false otherwise. public static bool AlmostEqualNorm(this T a, T b, double maximumAbsoluteError) where T : IPrecisionSupport { return AlmostEqualNorm(a.Norm(), b.Norm(), a.NormOfDifference(b), maximumAbsoluteError); } /// /// Compares two doubles and determines if they are equal /// within the specified maximum error. /// /// The norm of the first value (can be negative). /// The norm of the second value (can be negative). /// The norm of the difference of the two values (can be negative). /// The accuracy required for being almost equal. /// True if both doubles are almost equal up to the specified maximum error, false otherwise. public static bool AlmostEqualNormRelative(this double a, double b, double diff, double maximumError) { // If A or B are infinity (positive or negative) then // only return true if they are exactly equal to each other - // that is, if they are both infinities of the same sign. if (double.IsInfinity(a) || double.IsInfinity(b)) { return a == b; } // If A or B are a NAN, return false. NANs are equal to nothing, // not even themselves. if (double.IsNaN(a) || double.IsNaN(b)) { return false; } // If one is almost zero, fall back to absolute equality if (Math.Abs(a) < DoublePrecision || Math.Abs(b) < DoublePrecision) { return Math.Abs(diff) < maximumError; } if ((a == 0 && Math.Abs(b) < maximumError) || (b == 0 && Math.Abs(a) < maximumError)) { return true; } return Math.Abs(diff) < maximumError * Math.Max(Math.Abs(a), Math.Abs(b)); } /// /// Compares two doubles and determines if they are equal /// within the specified maximum error. /// /// The first value. /// The second value. /// The accuracy required for being almost equal. /// True if both doubles are almost equal up to the specified maximum error, false otherwise. public static bool AlmostEqualNormRelative(this T a, T b, double maximumError) where T : IPrecisionSupport { return AlmostEqualNormRelative(a.Norm(), b.Norm(), a.NormOfDifference(b), maximumError); } /// /// Compares two doubles and determines if they are equal within /// the specified maximum error. /// /// The first value. /// The second value. /// The accuracy required for being almost equal. public static bool AlmostEqual(this double a, double b, double maximumAbsoluteError) { return AlmostEqualNorm(a, b, a - b, maximumAbsoluteError); } /// /// Compares two complex and determines if they are equal within /// the specified maximum error. /// /// The first value. /// The second value. /// The accuracy required for being almost equal. public static bool AlmostEqual(this float a, float b, double maximumAbsoluteError) { return AlmostEqualNorm(a, b, a - b, maximumAbsoluteError); } /// /// Compares two complex and determines if they are equal within /// the specified maximum error. /// /// The first value. /// The second value. /// The accuracy required for being almost equal. public static bool AlmostEqual(this Complex a, Complex b, double maximumAbsoluteError) { return AlmostEqualNorm(a.Norm(), b.Norm(), a.NormOfDifference(b), maximumAbsoluteError); } /// /// Compares two complex and determines if they are equal within /// the specified maximum error. /// /// The first value. /// The second value. /// The accuracy required for being almost equal. public static bool AlmostEqual(this Complex32 a, Complex32 b, double maximumAbsoluteError) { return AlmostEqualNorm(a.Norm(), b.Norm(), a.NormOfDifference(b), maximumAbsoluteError); } /// /// Compares two doubles and determines if they are equal within /// the specified maximum error. /// /// The first value. /// The second value. /// The accuracy required for being almost equal. public static bool AlmostEqualRelative(this double a, double b, double maximumError) { return AlmostEqualNormRelative(a, b, a - b, maximumError); } /// /// Compares two complex and determines if they are equal within /// the specified maximum error. /// /// The first value. /// The second value. /// The accuracy required for being almost equal. public static bool AlmostEqualRelative(this float a, float b, double maximumError) { return AlmostEqualNormRelative(a, b, a - b, maximumError); } /// /// Compares two complex and determines if they are equal within /// the specified maximum error. /// /// The first value. /// The second value. /// The accuracy required for being almost equal. public static bool AlmostEqualRelative(this Complex a, Complex b, double maximumError) { return AlmostEqualNormRelative(a.Norm(), b.Norm(), a.NormOfDifference(b), maximumError); } /// /// Compares two complex and determines if they are equal within /// the specified maximum error. /// /// The first value. /// The second value. /// The accuracy required for being almost equal. public static bool AlmostEqualRelative(this Complex32 a, Complex32 b, double maximumError) { return AlmostEqualNormRelative(a.Norm(), b.Norm(), a.NormOfDifference(b), maximumError); } /// /// Checks whether two real numbers are almost equal. /// /// The first number /// The second number /// true if the two values differ by no more than 10 * 2^(-52); false otherwise. public static bool AlmostEqual(this double a, double b) { return AlmostEqualNorm(a, b, a - b, DefaultDoubleAccuracy); } /// /// Checks whether two real numbers are almost equal. /// /// The first number /// The second number /// true if the two values differ by no more than 10 * 2^(-52); false otherwise. public static bool AlmostEqual(this float a, float b) { return AlmostEqualNorm(a, b, a - b, DefaultSingleAccuracy); } /// /// Checks whether two Complex numbers are almost equal. /// /// The first number /// The second number /// true if the two values differ by no more than 10 * 2^(-52); false otherwise. public static bool AlmostEqual(this Complex a, Complex b) { return AlmostEqualNorm(a.Norm(), b.Norm(), a.NormOfDifference(b), DefaultDoubleAccuracy); } /// /// Checks whether two Complex numbers are almost equal. /// /// The first number /// The second number /// true if the two values differ by no more than 10 * 2^(-52); false otherwise. public static bool AlmostEqual(this Complex32 a, Complex32 b) { return AlmostEqualNorm(a.Norm(), b.Norm(), a.NormOfDifference(b), DefaultSingleAccuracy); } /// /// Checks whether two real numbers are almost equal. /// /// The first number /// The second number /// true if the two values differ by no more than 10 * 2^(-52); false otherwise. public static bool AlmostEqualRelative(this double a, double b) { return AlmostEqualNormRelative(a, b, a - b, DefaultDoubleAccuracy); } /// /// Checks whether two real numbers are almost equal. /// /// The first number /// The second number /// true if the two values differ by no more than 10 * 2^(-52); false otherwise. public static bool AlmostEqualRelative(this float a, float b) { return AlmostEqualNormRelative(a, b, a - b, DefaultSingleAccuracy); } /// /// Checks whether two Complex numbers are almost equal. /// /// The first number /// The second number /// true if the two values differ by no more than 10 * 2^(-52); false otherwise. public static bool AlmostEqualRelative(this Complex a, Complex b) { return AlmostEqualNormRelative(a.Norm(), b.Norm(), a.NormOfDifference(b), DefaultDoubleAccuracy); } /// /// Checks whether two Complex numbers are almost equal. /// /// The first number /// The second number /// true if the two values differ by no more than 10 * 2^(-52); false otherwise. public static bool AlmostEqualRelative(this Complex32 a, Complex32 b) { return AlmostEqualNormRelative(a.Norm(), b.Norm(), a.NormOfDifference(b), DefaultSingleAccuracy); } /// /// Compares two doubles and determines if they are equal to within the specified number of decimal places or not, using the /// number of decimal places as an absolute measure. /// /// /// /// The values are equal if the difference between the two numbers is smaller than 0.5e-decimalPlaces. We divide by /// two so that we have half the range on each side of the numbers, e.g. if == 2, then 0.01 will equal between /// 0.005 and 0.015, but not 0.02 and not 0.00 /// /// /// The norm of the first value (can be negative). /// The norm of the second value (can be negative). /// The norm of the difference of the two values (can be negative). /// The number of decimal places. public static bool AlmostEqualNorm(this double a, double b, double diff, int decimalPlaces) { // If A or B are a NAN, return false. NANs are equal to nothing, // not even themselves. if (double.IsNaN(a) || double.IsNaN(b)) { return false; } // If A or B are infinity (positive or negative) then // only return true if they are exactly equal to each other - // that is, if they are both infinities of the same sign. if (double.IsInfinity(a) || double.IsInfinity(b)) { return a == b; } // The values are equal if the difference between the two numbers is smaller than // 10^(-numberOfDecimalPlaces). We divide by two so that we have half the range // on each side of the numbers, e.g. if decimalPlaces == 2, // then 0.01 will equal between 0.005 and 0.015, but not 0.02 and not 0.00 return Math.Abs(diff) < Math.Pow(10, -decimalPlaces) / 2d; } /// /// Compares two doubles and determines if they are equal to within the specified number of decimal places or not, using the /// number of decimal places as an absolute measure. /// /// /// /// The values are equal if the difference between the two numbers is smaller than 0.5e-decimalPlaces. We divide by /// two so that we have half the range on each side of the numbers, e.g. if == 2, then 0.01 will equal between /// 0.005 and 0.015, but not 0.02 and not 0.00 /// /// /// The first value. /// The second value. /// The number of decimal places. public static bool AlmostEqualNorm(this T a, T b, int decimalPlaces) where T : IPrecisionSupport { return AlmostEqualNorm(a.Norm(), b.Norm(), a.NormOfDifference(b), decimalPlaces); } /// /// Compares two doubles and determines if they are equal to within the specified number of decimal places or not. If the numbers /// are very close to zero an absolute difference is compared, otherwise the relative difference is compared. /// /// /// /// The values are equal if the difference between the two numbers is smaller than 10^(-numberOfDecimalPlaces). We divide by /// two so that we have half the range on each side of the numbers, e.g. if == 2, then 0.01 will equal between /// 0.005 and 0.015, but not 0.02 and not 0.00 /// /// /// The norm of the first value (can be negative). /// The norm of the second value (can be negative). /// The norm of the difference of the two values (can be negative). /// The number of decimal places. /// Thrown if is smaller than zero. public static bool AlmostEqualNormRelative(this double a, double b, double diff, int decimalPlaces) { if (decimalPlaces < 0) { // Can't have a negative number of decimal places throw new ArgumentOutOfRangeException(nameof(decimalPlaces)); } // If A or B are a NAN, return false. NANs are equal to nothing, // not even themselves. if (double.IsNaN(a) || double.IsNaN(b)) { return false; } // If A or B are infinity (positive or negative) then // only return true if they are exactly equal to each other - // that is, if they are both infinities of the same sign. if (double.IsInfinity(a) || double.IsInfinity(b)) { return a == b; } // If both numbers are equal, get out now. This should remove the possibility of both numbers being zero // and any problems associated with that. if (a.Equals(b)) { return true; } // If one is almost zero, fall back to absolute equality if (Math.Abs(a) < DoublePrecision || Math.Abs(b) < DoublePrecision) { // The values are equal if the difference between the two numbers is smaller than // 10^(-numberOfDecimalPlaces). We divide by two so that we have half the range // on each side of the numbers, e.g. if decimalPlaces == 2, // then 0.01 will equal between 0.005 and 0.015, but not 0.02 and not 0.00 return Math.Abs(diff) < Math.Pow(10, -decimalPlaces) / 2d; } // If the magnitudes of the two numbers are equal to within one magnitude the numbers could potentially be equal int magnitudeOfFirst = Magnitude(a); int magnitudeOfSecond = Magnitude(b); int magnitudeOfMax = Math.Max(magnitudeOfFirst, magnitudeOfSecond); if (magnitudeOfMax > (Math.Min(magnitudeOfFirst, magnitudeOfSecond) + 1)) { return false; } // The values are equal if the difference between the two numbers is smaller than // 10^(-numberOfDecimalPlaces). We divide by two so that we have half the range // on each side of the numbers, e.g. if decimalPlaces == 2, // then 0.01 will equal between 0.00995 and 0.01005, but not 0.0015 and not 0.0095 return Math.Abs(diff) < Math.Pow(10, magnitudeOfMax - decimalPlaces) / 2d; } /// /// Compares two doubles and determines if they are equal to within the specified number of decimal places or not. If the numbers /// are very close to zero an absolute difference is compared, otherwise the relative difference is compared. /// /// /// /// The values are equal if the difference between the two numbers is smaller than 10^(-numberOfDecimalPlaces). We divide by /// two so that we have half the range on each side of the numbers, e.g. if == 2, then 0.01 will equal between /// 0.005 and 0.015, but not 0.02 and not 0.00 /// /// /// The first value. /// The second value. /// The number of decimal places. public static bool AlmostEqualNormRelative(this T a, T b, int decimalPlaces) where T : IPrecisionSupport { return AlmostEqualNormRelative(a.Norm(), b.Norm(), a.NormOfDifference(b), decimalPlaces); } /// /// Compares two doubles and determines if they are equal to within the specified number of decimal places or not, using the /// number of decimal places as an absolute measure. /// /// The first value. /// The second value. /// The number of decimal places. public static bool AlmostEqual(this double a, double b, int decimalPlaces) { return AlmostEqualNorm(a, b, a - b, decimalPlaces); } /// /// Compares two doubles and determines if they are equal to within the specified number of decimal places or not, using the /// number of decimal places as an absolute measure. /// /// The first value. /// The second value. /// The number of decimal places. public static bool AlmostEqual(this float a, float b, int decimalPlaces) { return AlmostEqualNorm(a, b, a - b, decimalPlaces); } /// /// Compares two doubles and determines if they are equal to within the specified number of decimal places or not, using the /// number of decimal places as an absolute measure. /// /// The first value. /// The second value. /// The number of decimal places. public static bool AlmostEqual(this Complex a, Complex b, int decimalPlaces) { return AlmostEqualNorm(a.Norm(), b.Norm(), a.NormOfDifference(b), decimalPlaces); } /// /// Compares two doubles and determines if they are equal to within the specified number of decimal places or not, using the /// number of decimal places as an absolute measure. /// /// The first value. /// The second value. /// The number of decimal places. public static bool AlmostEqual(this Complex32 a, Complex32 b, int decimalPlaces) { return AlmostEqualNorm(a.Norm(), b.Norm(), a.NormOfDifference(b), decimalPlaces); } /// /// Compares two doubles and determines if they are equal to within the specified number of decimal places or not. If the numbers /// are very close to zero an absolute difference is compared, otherwise the relative difference is compared. /// /// The first value. /// The second value. /// The number of decimal places. public static bool AlmostEqualRelative(this double a, double b, int decimalPlaces) { return AlmostEqualNormRelative(a, b, a - b, decimalPlaces); } /// /// Compares two doubles and determines if they are equal to within the specified number of decimal places or not. If the numbers /// are very close to zero an absolute difference is compared, otherwise the relative difference is compared. /// /// The first value. /// The second value. /// The number of decimal places. public static bool AlmostEqualRelative(this float a, float b, int decimalPlaces) { return AlmostEqualNormRelative(a, b, a - b, decimalPlaces); } /// /// Compares two doubles and determines if they are equal to within the specified number of decimal places or not. If the numbers /// are very close to zero an absolute difference is compared, otherwise the relative difference is compared. /// /// The first value. /// The second value. /// The number of decimal places. public static bool AlmostEqualRelative(this Complex a, Complex b, int decimalPlaces) { return AlmostEqualNormRelative(a.Norm(), b.Norm(), a.NormOfDifference(b), decimalPlaces); } /// /// Compares two doubles and determines if they are equal to within the specified number of decimal places or not. If the numbers /// are very close to zero an absolute difference is compared, otherwise the relative difference is compared. /// /// The first value. /// The second value. /// The number of decimal places. public static bool AlmostEqualRelative(this Complex32 a, Complex32 b, int decimalPlaces) { return AlmostEqualNormRelative(a.Norm(), b.Norm(), a.NormOfDifference(b), decimalPlaces); } /// /// Compares two doubles and determines if they are equal to within the tolerance or not. Equality comparison is based on the binary representation. /// /// /// /// Determines the 'number' of floating point numbers between two values (i.e. the number of discrete steps /// between the two numbers) and then checks if that is within the specified tolerance. So if a tolerance /// of 1 is passed then the result will be true only if the two numbers have the same binary representation /// OR if they are two adjacent numbers that only differ by one step. /// /// /// The comparison method used is explained in http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm . The article /// at http://www.extremeoptimization.com/resources/Articles/FPDotNetConceptsAndFormats.aspx explains how to transform the C code to /// .NET enabled code without using pointers and unsafe code. /// /// /// The first value. /// The second value. /// The maximum number of floating point values between the two values. Must be 1 or larger. /// Thrown if is smaller than one. public static bool AlmostEqualNumbersBetween(this double a, double b, long maxNumbersBetween) { // Make sure maxNumbersBetween is non-negative and small enough that the // default NAN won't compare as equal to anything. if (maxNumbersBetween < 1) { throw new ArgumentOutOfRangeException(nameof(maxNumbersBetween)); } // If A or B are infinity (positive or negative) then // only return true if they are exactly equal to each other - // that is, if they are both infinities of the same sign. if (double.IsInfinity(a) || double.IsInfinity(b)) { return a == b; } // If A or B are a NAN, return false. NANs are equal to nothing, // not even themselves. if (double.IsNaN(a) || double.IsNaN(b)) { return false; } // Get the first double and convert it to an integer value (by using the binary representation) long firstUlong = AsDirectionalInt64(a); // Get the second double and convert it to an integer value (by using the binary representation) long secondUlong = AsDirectionalInt64(b); // Now compare the values. // Note that this comparison can overflow so we'll approach this differently // Do note that we could overflow this way too. We should probably check that we don't. return (a > b) ? (secondUlong + maxNumbersBetween >= firstUlong) : (firstUlong + maxNumbersBetween >= secondUlong); } /// /// Compares two floats and determines if they are equal to within the tolerance or not. Equality comparison is based on the binary representation. /// /// The first value. /// The second value. /// The maximum number of floating point values between the two values. Must be 1 or larger. /// Thrown if is smaller than one. public static bool AlmostEqualNumbersBetween(this float a, float b, int maxNumbersBetween) { // Make sure maxNumbersBetween is non-negative and small enough that the // default NAN won't compare as equal to anything. if (maxNumbersBetween < 1) { throw new ArgumentOutOfRangeException(nameof(maxNumbersBetween)); } // If A or B are infinity (positive or negative) then // only return true if they are exactly equal to each other - // that is, if they are both infinities of the same sign. if (float.IsInfinity(a) || float.IsInfinity(b)) { return a == b; } // If A or B are a NAN, return false. NANs are equal to nothing, // not even themselves. if (float.IsNaN(a) || float.IsNaN(b)) { return false; } // Get the first float and convert it to an integer value (by using the binary representation) int firstUlong = AsDirectionalInt32(a); // Get the second float and convert it to an integer value (by using the binary representation) int secondUlong = AsDirectionalInt32(b); // Now compare the values. // Note that this comparison can overflow so we'll approach this differently // Do note that we could overflow this way too. We should probably check that we don't. return (a > b) ? (secondUlong + maxNumbersBetween >= firstUlong) : (firstUlong + maxNumbersBetween >= secondUlong); } /// /// Compares two lists of doubles and determines if they are equal within the /// specified maximum error. /// /// The first value list. /// The second value list. /// The accuracy required for being almost equal. public static bool ListAlmostEqual(this IList a, IList b, double maximumAbsoluteError) { return ListForAll(a, b, AlmostEqual, maximumAbsoluteError); } /// /// Compares two lists of doubles and determines if they are equal within the /// specified maximum error. /// /// The first value list. /// The second value list. /// The accuracy required for being almost equal. public static bool ListAlmostEqual(this IList a, IList b, double maximumAbsoluteError) { return ListForAll(a, b, AlmostEqual, maximumAbsoluteError); } /// /// Compares two lists of doubles and determines if they are equal within the /// specified maximum error. /// /// The first value list. /// The second value list. /// The accuracy required for being almost equal. public static bool ListAlmostEqual(this IList a, IList b, double maximumAbsoluteError) { return ListForAll(a, b, AlmostEqual, maximumAbsoluteError); } /// /// Compares two lists of doubles and determines if they are equal within the /// specified maximum error. /// /// The first value list. /// The second value list. /// The accuracy required for being almost equal. public static bool ListAlmostEqual(this IList a, IList b, double maximumAbsoluteError) { return ListForAll(a, b, AlmostEqual, maximumAbsoluteError); } /// /// Compares two lists of doubles and determines if they are equal within the /// specified maximum error. /// /// The first value list. /// The second value list. /// The accuracy required for being almost equal. public static bool ListAlmostEqualRelative(this IList a, IList b, double maximumError) { return ListForAll(a, b, AlmostEqualRelative, maximumError); } /// /// Compares two lists of doubles and determines if they are equal within the /// specified maximum error. /// /// The first value list. /// The second value list. /// The accuracy required for being almost equal. public static bool ListAlmostEqualRelative(this IList a, IList b, double maximumError) { return ListForAll(a, b, AlmostEqualRelative, maximumError); } /// /// Compares two lists of doubles and determines if they are equal within the /// specified maximum error. /// /// The first value list. /// The second value list. /// The accuracy required for being almost equal. public static bool ListAlmostEqualRelative(this IList a, IList b, double maximumError) { return ListForAll(a, b, AlmostEqualRelative, maximumError); } /// /// Compares two lists of doubles and determines if they are equal within the /// specified maximum error. /// /// The first value list. /// The second value list. /// The accuracy required for being almost equal. public static bool ListAlmostEqualRelative(this IList a, IList b, double maximumError) { return ListForAll(a, b, AlmostEqualRelative, maximumError); } /// /// Compares two lists of doubles and determines if they are equal within the /// specified maximum error. /// /// The first value list. /// The second value list. /// The number of decimal places. public static bool ListAlmostEqual(this IList a, IList b, int decimalPlaces) { return ListForAll(a, b, AlmostEqual, decimalPlaces); } /// /// Compares two lists of doubles and determines if they are equal within the /// specified maximum error. /// /// The first value list. /// The second value list. /// The number of decimal places. public static bool ListAlmostEqual(this IList a, IList b, int decimalPlaces) { return ListForAll(a, b, AlmostEqual, decimalPlaces); } /// /// Compares two lists of doubles and determines if they are equal within the /// specified maximum error. /// /// The first value list. /// The second value list. /// The number of decimal places. public static bool ListAlmostEqual(this IList a, IList b, int decimalPlaces) { return ListForAll(a, b, AlmostEqual, decimalPlaces); } /// /// Compares two lists of doubles and determines if they are equal within the /// specified maximum error. /// /// The first value list. /// The second value list. /// The number of decimal places. public static bool ListAlmostEqual(this IList a, IList b, int decimalPlaces) { return ListForAll(a, b, AlmostEqual, decimalPlaces); } /// /// Compares two lists of doubles and determines if they are equal within the /// specified maximum error. /// /// The first value list. /// The second value list. /// The number of decimal places. public static bool ListAlmostEqualRelative(this IList a, IList b, int decimalPlaces) { return ListForAll(a, b, AlmostEqualRelative, decimalPlaces); } /// /// Compares two lists of doubles and determines if they are equal within the /// specified maximum error. /// /// The first value list. /// The second value list. /// The number of decimal places. public static bool ListAlmostEqualRelative(this IList a, IList b, int decimalPlaces) { return ListForAll(a, b, AlmostEqualRelative, decimalPlaces); } /// /// Compares two lists of doubles and determines if they are equal within the /// specified maximum error. /// /// The first value list. /// The second value list. /// The number of decimal places. public static bool ListAlmostEqualRelative(this IList a, IList b, int decimalPlaces) { return ListForAll(a, b, AlmostEqualRelative, decimalPlaces); } /// /// Compares two lists of doubles and determines if they are equal within the /// specified maximum error. /// /// The first value list. /// The second value list. /// The number of decimal places. public static bool ListAlmostEqualRelative(this IList a, IList b, int decimalPlaces) { return ListForAll(a, b, AlmostEqualRelative, decimalPlaces); } /// /// Compares two lists of doubles and determines if they are equal within the /// specified maximum error. /// /// The first value list. /// The second value list. /// The accuracy required for being almost equal. public static bool ListAlmostEqualNorm(this IList a, IList b, double maximumAbsoluteError) where T : IPrecisionSupport { if (a == null && b == null) { return true; } if (a == null || b == null || a.Count != b.Count) { return false; } for (int i = 0; i < a.Count; i++) { if (!AlmostEqualNorm(a[i], b[i], maximumAbsoluteError)) { return false; } } return true; } /// /// Compares two lists of doubles and determines if they are equal within the /// specified maximum error. /// /// The first value list. /// The second value list. /// The accuracy required for being almost equal. public static bool ListAlmostEqualNormRelative(this IList a, IList b, double maximumError) where T : IPrecisionSupport { if (a == null && b == null) { return true; } if (a == null || b == null || a.Count != b.Count) { return false; } for (int i = 0; i < a.Count; i++) { if (!AlmostEqualNormRelative(a[i], b[i], maximumError)) { return false; } } return true; } private static bool ListForAll(IList a, IList b, Func predicate, TP parameter) { if (a == null && b == null) { return true; } if (a == null || b == null || a.Count != b.Count) { return false; } for (int i = 0; i < a.Count; i++) { if (!predicate(a[i], b[i], parameter)) { return false; } } return true; } /// /// Compares two vectors and determines if they are equal within the specified maximum error. /// /// The first value. /// The second value. /// The accuracy required for being almost equal. public static bool AlmostEqual(this Vector a, Vector b, double maximumAbsoluteError) where T : struct, IEquatable, IFormattable { return AlmostEqualNorm(a.L2Norm(), b.L2Norm(), (a - b).L2Norm(), maximumAbsoluteError); } /// /// Compares two vectors and determines if they are equal within the specified maximum error. /// /// The first value. /// The second value. /// The accuracy required for being almost equal. public static bool AlmostEqualRelative(this Vector a, Vector b, double maximumError) where T : struct, IEquatable, IFormattable { return AlmostEqualNormRelative(a.L2Norm(), b.L2Norm(), (a - b).L2Norm(), maximumError); } /// /// Compares two vectors and determines if they are equal to within the specified number /// of decimal places or not, using the number of decimal places as an absolute measure. /// /// The first value. /// The second value. /// The number of decimal places. public static bool AlmostEqual(this Vector a, Vector b, int decimalPlaces) where T : struct, IEquatable, IFormattable { return AlmostEqualNorm(a.L2Norm(), b.L2Norm(), (a - b).L2Norm(), decimalPlaces); } /// /// Compares two vectors and determines if they are equal to within the specified number of decimal places or not. /// If the numbers are very close to zero an absolute difference is compared, otherwise the relative difference is compared. /// /// The first value. /// The second value. /// The number of decimal places. public static bool AlmostEqualRelative(this Vector a, Vector b, int decimalPlaces) where T : struct, IEquatable, IFormattable { return AlmostEqualNormRelative(a.L2Norm(), b.L2Norm(), (a - b).L2Norm(), decimalPlaces); } /// /// Compares two matrices and determines if they are equal within the specified maximum error. /// /// The first value. /// The second value. /// The accuracy required for being almost equal. public static bool AlmostEqual(this Matrix a, Matrix b, double maximumAbsoluteError) where T : struct, IEquatable, IFormattable { return AlmostEqualNorm(a.L2Norm(), b.L2Norm(), (a - b).L2Norm(), maximumAbsoluteError); } /// /// Compares two matrices and determines if they are equal within the specified maximum error. /// /// The first value. /// The second value. /// The accuracy required for being almost equal. public static bool AlmostEqualRelative(this Matrix a, Matrix b, double maximumError) where T : struct, IEquatable, IFormattable { return AlmostEqualNormRelative(a.L2Norm(), b.L2Norm(), (a - b).L2Norm(), maximumError); } /// /// Compares two matrices and determines if they are equal to within the specified number /// of decimal places or not, using the number of decimal places as an absolute measure. /// /// The first value. /// The second value. /// The number of decimal places. public static bool AlmostEqual(this Matrix a, Matrix b, int decimalPlaces) where T : struct, IEquatable, IFormattable { return AlmostEqualNorm(a.L2Norm(), b.L2Norm(), (a - b).L2Norm(), decimalPlaces); } /// /// Compares two matrices and determines if they are equal to within the specified number of decimal places or not. /// If the numbers are very close to zero an absolute difference is compared, otherwise the relative difference is compared. /// /// The first value. /// The second value. /// The number of decimal places. public static bool AlmostEqualRelative(this Matrix a, Matrix b, int decimalPlaces) where T : struct, IEquatable, IFormattable { return AlmostEqualNormRelative(a.L2Norm(), b.L2Norm(), (a - b).L2Norm(), decimalPlaces); } } }