//SOURCE: https://github.com/mathnet/mathnet-numerics/blob/master/src/Numerics/Precision.cs
// https://github.com/mathnet/mathnet-numerics/blob/master/src/Numerics/Precision.Equality.cs
// http://referencesource.microsoft.com/#WindowsBase/Shared/MS/Internal/DoubleUtil.cs
// http://stackoverflow.com/questions/2411392/double-epsilon-for-equality-greater-than-less-than-less-than-or-equal-to-gre
public static class DoubleExtensions
/// The smallest positive number that when SUBTRACTED from 1D yields a result different from 1D.
/// This number has the following properties:
/// (1 - NegativeMachineEpsilon) < 1 and
/// (1 + NegativeMachineEpsilon) == 1
public static readonly double MeasuredNegativeMachineEpsilon = MeasureNegativeMachineEpsilon();
/// The smallest positive number that when ADDED to 1D yields a result different from 1D.
/// This number has the following properties:
/// (1 - PositiveDoublePrecision) < 1 and
/// (1 + PositiveDoublePrecision) > 1
public static readonly double MeasuredPositiveMachineEpsilon = MeasurePositiveMachineEpsilon();
/// The smallest positive number that when SUBTRACTED from 1D yields a result different from 1D.
/// The value is derived from 2^(-53) = 1.1102230246251565e-16, where IEEE 754 binary64 "double precision" floating point numbers have a significand precision that utilize 53 bits.
/// This number has the following properties:
/// (1 - NegativeMachineEpsilon) < 1 and
/// (1 + NegativeMachineEpsilon) == 1
public const double NegativeMachineEpsilon = 1.1102230246251565e-16D; //Math.Pow(2, -53);
/// The smallest positive number that when ADDED to 1D yields a result different from 1D.
/// The value is derived from 2 * 2^(-53) = 2.2204460492503131e-16, where IEEE 754 binary64 "double precision" floating point numbers have a significand precision that utilize 53 bits.
/// This number has the following properties:
/// (1 - PositiveDoublePrecision) < 1 and
/// (1 + PositiveDoublePrecision) > 1
public const double PositiveMachineEpsilon = 2D * NegativeMachineEpsilon;
public static bool IsClose(this double value1, double value2,
double maximumAbsoluteError = DefaultDoubleAccuracy)
if (double.IsInfinity(value1) || double.IsInfinity(value2))
return Equals(value1, value2);
if (double.IsNaN(value1) || double.IsNaN(value2))
var delta = value1 - value2;
//return Math.Abs(delta) <= maximumAbsoluteError;
if (delta > maximumAbsoluteError ||
delta < -maximumAbsoluteError)
public static bool LessThan(this double value1, double value2)
return (value1 < value2) && !IsClose(value1, value2);
public static bool GreaterThan(this double value1, double value2)
return (value1 > value2) && !IsClose(value1, value2);
public static bool LessThanOrClose(this double value1, double value2)
return (value1 < value2) || IsClose(value1, value2);
public static bool GreaterThanOrClose(this double value1, double value2)
return (value1 > value2) || IsClose(value1, value2);
public static bool IsOne(this double value)
//return Math.Abs(delta) <= PositiveMachineEpsilon;
if (delta > PositiveMachineEpsilon ||
delta < -PositiveMachineEpsilon)
public static bool IsZero(this double value)
//return Math.Abs(value) <= PositiveMachineEpsilon;
if (value > PositiveMachineEpsilon ||
value < -PositiveMachineEpsilon)
/// 判断两个 <see cref="T:System.Double" /> 值是否近似相等。
/// <param name="d1">值1。</param>
/// <param name="d2">值2。</param>
/// <param name="tolerance">近似容差。</param>
public static bool NearlyEquals(double d1, double d2, double tolerance = 1E-05)
return IsClose(d1, d2, tolerance);
private static double MeasureNegativeMachineEpsilon()
var nextEpsilon = epsilon / 2D;
if (NearlyEquals(1D - nextEpsilon, 1D)) //if nextEpsilon is too small
private static double MeasurePositiveMachineEpsilon()
var nextEpsilon = epsilon / 2D;
if (NearlyEquals((1D + nextEpsilon), 1D)) //if nextEpsilon is too small
private const double DefaultDoubleAccuracy = NegativeMachineEpsilon * 10D;