下一个更高/更低的IEEE双精度数

时间:2009-08-07 16:59:57

标签: double ieee-754 floating-point-precision

我正在进行高精度的科学计算。在寻找各种效果的最佳表示时,我不断提出想要获得下一个更高(或更低)双精度数的理由。基本上,我想要做的是在double的内部表示中添加一个最低位。

难点在于IEEE格式不完全一致。如果要使用低级代码并实际将一个代码添加到最低有效位,则生成的格式可能不是下一个可用的双精度型。例如,它可能是一个特殊的案例编号,例如PositiveInfinity或NaN。还有一些次正常值,我不认为这些值,但它们似乎具有与“正常”模式不同的特定位模式。

“epsilon”值可用,但我从未理解其定义。由于double值的间隔不均匀,因此不能将单个值添加到double中以产生下一个更高的值。

我真的不明白为什么IEEE没有指定一个函数来获得下一个更高或更低的值。我不可能是唯一需要它的人。

有没有办法获得下一个值(没有某种循环尝试添加越来越小的值)。

5 个答案:

答案 0 :(得分:13)

有一些功能可以完全执行,但它们可能取决于您使用的语言。两个例子:

  • 如果您可以访问一个体面的C99数学库,您可以使用nextafter(及其浮点和长双变体,nextafterfnextafterl);或者nexttoward家族(以长双作为第二个参数)。

  • 如果您编写Fortran,则可以使用nearest内在函数

如果您无法直接使用您的语言访问这些内容,您还可以查看它们是如何在免费提供的情况下实现的,例如this one

答案 1 :(得分:5)

正如Thorsten S.所说,这可以通过BitConverter类来完成,但是他的方法假设DoubleToInt64Bits方法返回double的内部字节结构,它就是不。该方法返回的整数实际上返回0和你之间的可表示双精度数。即最小的正双精度数由1表示,下一个最大双精度数表示为2,等等。负数从long.MinValue开始,远离0d。

所以你可以这样做:

public static double NextDouble(double value) {

    // Get the long representation of value:
    var longRep = BitConverter.DoubleToInt64Bits(value);

    long nextLong;
    if (longRep >= 0) // number is positive, so increment to go "up"
        nextLong = longRep + 1L;
    else if (longRep == long.MinValue) // number is -0
        nextLong = 1L;
    else  // number is negative, so decrement to go "up"
        nextLong = longRep - 1L;

    return BitConverter.Int64BitsToDouble(nextLong);
}

这不涉及InfinityNaN,,但如果您对此感到担心,可以查看这些内容并随意处理。

答案 2 :(得分:2)

是的,有办法。 在C#中:

       public static double getInc (double d)
        {
                // Check for special values
                if (double.IsPositiveInfinity(d) || double.IsNegativeInfinity(d))
                    return d;
                if (double.IsNaN(d))
                    return d;

                // Translate the double into binary representation
                ulong bits = (ulong)BitConverter.DoubleToInt64Bits(d);
                // Mask out the mantissa bits
                bits &= 0xfff0000000000000L;
                // Reduce exponent by 52 bits, so subtract 52 from the mantissa.
                // First check if number is great enough.
                ulong testWithoutSign = bits & 0x7ff0000000000000L;
                if (testWithoutSign > 0x0350000000000000L)
                  bits -= 0x0350000000000000L;
                else
                  bits = 0x0000000000000001L;
                return BitConverter.Int64BitsToDouble((long)bits);
}

可以增加和减少增加。

答案 3 :(得分:1)

我不确定我是否正在关注你的问题。当然,IEEE标准 完全统一?例如,请查看wikipedia article的摘要,了解双精度数字。

3ff0 0000 0000 0000   = 1
3ff0 0000 0000 0001   = 1.0000000000000002, the next higher number > 1
3ff0 0000 0000 0002   = 1.0000000000000004

以二进制或十六进制表示递增最低有效位有什么问题?

就特殊数字而言(无穷大,NaN等),它们定义得很好,而且它们并不多。限制类似地定义。

既然你已经明白了这一点,我希望自己有一个错误的结局。如果这不足以解决您的问题,您是否可以尝试澄清您想要实现的目标?你的目标是什么?

答案 4 :(得分:1)

关于epsilon函数,它估计二进制双数可能与十进制值的近似值有多远。这是因为,对于非常大的正或负十进制数或非常小的正或负十进制数,它们中的许多映射到与double相同的二进制表示。尝试一些非常非常大或非常非常小的十进制数,从它们创建双精度然后转换回十进制数。你会发现你不会得到相同的十进制数,而是最接近的那个。

对于附近的值(接近相对于双倍数可以表示的巨大十进制值范围)1或-1,epsilon将为零或非常非常小。对于逐渐朝向+或 - 无穷大或零的值,epsilon将开始增长。在非常接近零或无穷大的值处,epsilon将非常大,因为这些范围中的十进制值的可用二进制表示非常非常稀疏。