维基百科关于双精度浮点数的页面在这里:
http://en.wikipedia.org/wiki/Double_precision_floating-point_format
我写了一些代码来分解
double
格式的二进制表示,减少尾数并重新组成结果。由于尾数中有一个隐含的位,我们必须检查它并相应地修改指数,在接近极限时可能会失败。
以下是代码:
public static double PrevDouble(double src)
{
if (double.IsInfinity(src) || double.IsNaN(src))
return src;
if (src == 0)
return -double.MinValue;
byte[] srcbytes = System.BitConverter.GetBytes(src);
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]);
--mant;
if ((mant & ((ulong)1 << 52)) == 0)
{
mant <<= 1;
exp--;
}
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);
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
的结果为false,正如上面所示,实际上存在差异 :)