c# - 为什么将 double.epsilon 添加到一个值会产生相同的值,完全相等?

标签 c# unit-testing double double-precision epsilon

我有一个单元测试,测试边界:

[TestMethod]
[ExpectedException(typeof(ArgumentOutOfRangeException))]
public void CreateExtent_InvalidTop_ShouldThrowArgumentOutOfRangeException()
{
    var invalidTop = 90.0 + Double.Epsilon;
    new Extent(invalidTop, 0.0, 0.0, 0.0);
}

public static readonly double MAX_LAT = 90.0;

public Extent(double top, double right, double bottom, double left)
{
    if (top > GeoConstants.MAX_LAT)
        throw new ArgumentOutOfRangeException("top"); // not hit
}

我以为我可以通过向其添加最小可能的正 double 来使 90.0 超过边缘,但现在没有抛出异常,知道为什么吗?

在调试时,我看到 top 显示为 90,而它应该是 90.00000000...。

编辑: 我应该更认真地考虑一下,90+Double.Epsilon 会失去分辨率。似乎最好的方法是进行一些位移。

解决方案:

[TestMethod]
[ExpectedException(typeof(ArgumentOutOfRangeException))]
public void CreateExtent_InvalidTop_ShouldThrowArgumentOutOfRangeException()
{
    var invalidTop = Utility.IncrementTiny(90); // 90.000000000000014
    // var sameAsEpsilon = Utility.IncrementTiny(0);
    new Extent(invalidTop, 0, 0, 0);
}

/// <summary>
/// Increment a double-precision number by the smallest amount possible
/// </summary>
/// <param name="number">double-precision number</param>
/// <returns>incremented number</returns>
public static double IncrementTiny(double number)
{
    #region SANITY CHECKS
    if (Double.IsNaN(number) || Double.IsInfinity(number))
        throw new ArgumentOutOfRangeException("number");
    #endregion

    var bits = BitConverter.DoubleToInt64Bits(number);

    // if negative then go opposite way
    if (number > 0)
        return BitConverter.Int64BitsToDouble(bits + 1);
    else if (number < 0)
        return BitConverter.Int64BitsToDouble(bits - 1);
    else
        return Double.Epsilon;
}

/// <summary>
/// Decrement a double-precision number by the smallest amount possible
/// </summary>
/// <param name="number">double-precision number</param>
/// <returns>decremented number</returns>
public static double DecrementTiny(double number)
{
    #region SANITY CHECKS
    if (Double.IsNaN(number) || Double.IsInfinity(number))
        throw new ArgumentOutOfRangeException("number");
    #endregion

    var bits = BitConverter.DoubleToInt64Bits(number);

    // if negative then go opposite way
    if (number > 0)
        return BitConverter.Int64BitsToDouble(bits - 1);
    else if (number < 0)
        return BitConverter.Int64BitsToDouble(bits + 1);
    else
        return 0 - Double.Epsilon;
}

这就完成了工作。

最佳答案

根据 the documentation of Double.Epsilon :

The value of the Epsilon property reflects the smallest positive Double value that is significant in numeric operations or comparisons when the value of the Double instance is zero.

(强调我的。)

将它添加到 90.0 不会产生“90.0 之后的下一个最小值”,这只会再次产生 90.0。

关于c# - 为什么将 double.epsilon 添加到一个值会产生相同的值,完全相等?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27506477/

相关文章:

c - 使用 .* 宽度说明符调用 sprintf 时出现奇怪的警告

c# - 将 double 日期和时间值转换为另一个时区?

c# - 为什么我的 Uninstall 方法没有被调用?

c# - ReactiveCommand 的前后 Action

android - testAndroidTestCaseSetUpProperly 是做什么的

c# - 如何将数据从 UnitTest 传递到 LoadTest?

c# - 如何使用谓词实现 Task.WhenAny()

c# - 改进我的代码:正则表达式解析逗号分隔的数字列表

java - 为什么具有 Android 依赖项的基类实例可以进行单元测试?

c - 对于 double 值,如何不接收不是 scanf 中数字的字符。