我正在进行高精度的科学计算。在寻找各种效果的最佳表示时,我不断提出想要获得下一个更高(或更低)双精度数的理由。基本上,我想要做的是在double的内部表示中添加一个最低位。
难点在于IEEE格式不完全一致。如果要使用低级代码并实际将一个代码添加到最低有效位,则生成的格式可能不是下一个可用的双精度型。例如,它可能是一个特殊的案例编号,例如PositiveInfinity或NaN。还有一些次正常值,我不认为这些值,但它们似乎具有与“正常”模式不同的特定位模式。
“epsilon”值可用,但我从未理解其定义。由于double值的间隔不均匀,因此不能将单个值添加到double中以产生下一个更高的值。
我真的不明白为什么IEEE没有指定一个函数来获得下一个更高或更低的值。我不可能是唯一需要它的人。
有没有办法获得下一个值(没有某种循环尝试添加越来越小的值)。
答案 0 :(得分:13)
有一些功能可以完全执行,但它们可能取决于您使用的语言。两个例子:
如果您可以访问一个体面的C99数学库,您可以使用nextafter
(及其浮点和长双变体,nextafterf
和nextafterl
);或者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);
}
这不涉及Infinity
和NaN,
,但如果您对此感到担心,可以查看这些内容并随意处理。
答案 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将非常大,因为这些范围中的十进制值的可用二进制表示非常非常稀疏。