获取下一个最小的双号(Get next smallest Double number)

2019-07-21 07:04发布

作为单元测试的一部分,我需要测试一些边界条件。 一种方法接受System.Double参数。

是否有一种方式来获得下一个最小的双重价值? (即递减1个单位值的尾数)?

我认为使用Double.Epsilon但它只是从零最小的增量,因此对于较大的值不起作用,这是不可靠的(即9999999999 - Double.Epsilon == 9999999999 )。

那么,什么是需要这样的算法或代码:

NextSmallest(Double d) < d

...总是正确的。

Answer 1:

如果您的号码是有限的,你可以用一对夫妇在方便的方法BitConverter类:

long bits = BitConverter.DoubleToInt64Bits(value);
if (value > 0)
    return BitConverter.Int64BitsToDouble(bits - 1);
else if (value < 0)
    return BitConverter.Int64BitsToDouble(bits + 1);
else
    return -double.Epsilon;

IEEE-754格式被设计成组成指数和尾数位一起形成具有相同的顺序的浮点数的整数。 因此,要获得最大数量较少,则可以减去一个从这个号,如果数值为正,则可以添加一个,如果该值为负。

关键原因为什么这个作品是尾数的前导位不被存储。 如果你的尾数都是零,那么你的号码是二的幂。 如果从指数/尾数组合减去1,你让所有的人,你就会有从指数位借款。 换句话说:你有递减的指数,这是我们想要的东西。



Answer 2:

在双精度浮点维基百科页面是在这里: http://en.wikipedia.org/wiki/Double_precision_floating-point_format

为了好玩,我写了一些代码,以摆脱的二进制表示double格式,递减尾数和重新组成产生的两倍。 由于尾数的隐含位的,我们必须检查它并修改相应的指数,它可能无法接近极限。

下面的代码:

public static double PrevDouble(double src)
{
    // check for special values:
    if (double.IsInfinity(src) || double.IsNaN(src))
        return src;
    if (src == 0)
        return -double.MinValue;

    // get bytes from double
    byte[] srcbytes = System.BitConverter.GetBytes(src);

    // extract components
    byte sign = (byte)(srcbytes[7] & 0x80);
    ulong exp = ((((ulong)srcbytes[7]) & 0x7F) << 4) + (((ulong)srcbytes[6] >> 4) & 0x0F);
    ulong mant = ((ulong)1 << 52) | (((ulong)srcbytes[6] & 0x0F) << 48) | (((ulong)srcbytes[5]) << 40) | (((ulong)srcbytes[4]) << 32) | (((ulong)srcbytes[3]) << 24) | (((ulong)srcbytes[2]) << 16) | (((ulong)srcbytes[1]) << 8) | ((ulong)srcbytes[0]);

    // decrement mantissa
    --mant;

    // check if implied bit has been removed and shift if so
    if ((mant & ((ulong)1 << 52)) == 0)
    {
        mant <<= 1;
        exp--;
    }

    // build byte representation of modified value
    byte[] bytes = new byte[8];
    bytes[7] = (byte)((ulong)sign | ((exp >> 4) & 0x7F));
    bytes[6] = (byte)((((ulong)exp & 0x0F) << 4) | ((mant >> 48) & 0x0F));
    bytes[5] = (byte)((mant >> 40) & 0xFF);
    bytes[4] = (byte)((mant >> 32) & 0xFF);
    bytes[3] = (byte)((mant >> 24) & 0xFF);
    bytes[2] = (byte)((mant >> 16) & 0xFF);
    bytes[1] = (byte)((mant >> 8) & 0xFF);
    bytes[0] = (byte)(mant & 0xFF);

    // convert back to double and return
    double res = System.BitConverter.ToDouble(bytes, 0);
    return res;
}

所有这一切都为您提供了一个值是由在尾数最低位发生变化的初始值不同......在理论上:)

这是一个测试:

public static Main(string[] args)
{
    double test = 1.0/3;
    double prev = PrevDouble(test);
    Console.WriteLine("{0:r}, {1:r}, {2:r}", test, prev, test - prev);
}

给我的电脑上,结果如下:

0.33333333333333331, 0.33333333333333326, 5.5511151231257827E-17

也是有差别的,但可能低于舍入门槛。 表达test == prev的计算结果为假虽然,有如上述所示的实际差:)



文章来源: Get next smallest Double number