Các trang Wikipedia trên đôi chính xác dấu chấm động là ở đây: http://en.wikipedia.org/wiki/Double_precision_floating-point_format
Đối với niềm vui, tôi đã viết một số mã để thoát ra khỏi sự biểu diễn nhị phân của định dạng double
, decrements mantissa và recomposes các kết quả gấp đôi. Do bit ngầm trong phần định trị, chúng ta phải kiểm tra nó và sửa đổi số mũ cho phù hợp, và nó có thể thất bại gần các giới hạn.
Dưới đây là các mã:
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;
}
Tất cả mang đến cho bạn một giá trị khác với giá trị ban đầu của một sự thay đổi trong các bit thấp nhất của mantissa ... về mặt lý thuyết :)
Dưới đây là một thử nghiệm:
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);
}
Cung cấp cho kết quả như sau trên máy tính của tôi:
0.33333333333333331, 0.33333333333333326, 5.5511151231257827E-17
Sự khác biệt là có, nhưng có thể là dưới ngưỡng làm tròn. Khái niệm test == prev
là false mặc dù, và có một sự khác biệt thực tế như trình bày ở trên :)
Còn nếu bạn chỉ chia cho 10 – Hogan
Tôi nghĩ câu hỏi của bạn đã được trả lời tại đây: http://stackoverflow.com/a/2283565/1715579. –