C# double好用的扩展
了解过double在计算机中的存储方式的,应该知道double类型,要判断"相等"是很困难的,比如我们写出下面一行代码
if(a==b){//do something...}
此时编译器会提示这个判断不严谨,他推荐:
Math.Abs(a-b)<一个很小的数
于是乎,我在搜索引擎中搜索了一下,发现类似这种double类型的比较操作被封装成了工具方法,下面给出一个从lindexi的一篇博客中Copy来的工具类,以后可以放到自己的项目中使用。
/// <summary>
/// Double 的扩展
/// </summary>
//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
{
/// <summary>
/// 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
/// </summary>
public static readonly double MeasuredNegativeMachineEpsilon = MeasureNegativeMachineEpsilon();
/// <summary>
/// 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
/// </summary>
public static readonly double MeasuredPositiveMachineEpsilon = MeasurePositiveMachineEpsilon();
/// <summary>
/// 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
/// </summary>
public const double NegativeMachineEpsilon = 1.1102230246251565e-16D; //Math.Pow(2, -53);
/// <summary>
/// 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
/// </summary>
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))
{
return false;
}
var delta = value1 - value2;
//return Math.Abs(delta) <= maximumAbsoluteError;
if (delta > maximumAbsoluteError ||
delta < -maximumAbsoluteError)
{
return false;
}
return true;
}
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)
{
var delta = value - 1D;
//return Math.Abs(delta) <= PositiveMachineEpsilon;
if (delta > PositiveMachineEpsilon ||
delta < -PositiveMachineEpsilon)
{
return false;
}
return true;
}
public static bool IsZero(this double value)
{
//return Math.Abs(value) <= PositiveMachineEpsilon;
if (value > PositiveMachineEpsilon ||
value < -PositiveMachineEpsilon)
{
return false;
}
return true;
}
/// <summary>
/// 判断两个 <see cref="T:System.Double" /> 值是否近似相等。
/// </summary>
/// <param name="d1">值1。</param>
/// <param name="d2">值2。</param>
/// <param name="tolerance">近似容差。</param>
[PublicAPI]
public static bool NearlyEquals(double d1, double d2, double tolerance = 1E-05)
{
return IsClose(d1, d2, tolerance);
}
private static double MeasureNegativeMachineEpsilon()
{
var epsilon = 1D;
do
{
var nextEpsilon = epsilon / 2D;
if (NearlyEquals(1D - nextEpsilon, 1D)) //if nextEpsilon is too small
{
return epsilon;
}
epsilon = nextEpsilon;
} while (true);
}
private static double MeasurePositiveMachineEpsilon()
{
var epsilon = 1D;
do
{
var nextEpsilon = epsilon / 2D;
if (NearlyEquals((1D + nextEpsilon), 1D)) //if nextEpsilon is too small
{
return epsilon;
}
epsilon = nextEpsilon;
} while (true);
}
private const double DefaultDoubleAccuracy = NegativeMachineEpsilon * 10D;
}

浙公网安备 33010602011771号