获得(非零)双精度或浮点数的最小步长

Obtaining the smallest step size for a (non-zero) double or float

出于测试中边界值分析的目的,我一直在寻找 .Net 中双精度或浮点数的最小步长。这将允许我获得可以用双精度或浮点数表示的下一个更大和下一个更小的值。

double.epsilon, "applies only to Double instances that have a value of zero or an exponent of -1022".

假设我有一个任意的双精度数或浮点数。我可以在 .Net 中表示的下一个更大和下一个更小的值是什么?

根据MSDN文章,我实现了如下代码,看起来很合理:

private static int GetExponentWithMinorAdjustment(double value)
{
    //int indent = result.Length;

    // Convert the double to an 8-byte array.
    byte[] bytes = BitConverter.GetBytes(value);

    int exponent = (bytes[7] & 0x07F) << 4;
    exponent = exponent | ((bytes[6] & 0xF0) >> 4);
    int adjustment = exponent != 0 ? 1023 : 1022;

    return exponent != 0 ? exponent - 1 : exponent; ;
}

private static double NextLargerNumber(double value)
{
    // Cannot use double.epsilon * Math.Pow(2, GetExponentWithMinorAdjustment(value)) as this results in infinity
    return value + Math.Pow(2, GetExponentWithMinorAdjustment(value) - 1074));
}

上面代码的问题在于它看起来不稳定。注意三元运算符(灵感来自 MSDN 文章);调整的目的是什么?

此外,虽然几个测试的输出对于正 double 值看起来不错,但对于负值的结果似乎不太好(参见输出图像):

这个问题的可接受、正确和理想的解决方案是什么样的?

使用不安全代码将位直接映射到无符号整数,递增或递减,转换回来。

可能需要在 0 的边界和无穷大、Nan 等的特殊值处进行额外的特殊处理。