EDIT: Để nó hoạt động ngay bây giờ, trong khi bình thường hóa mantiss, điều quan trọng là trước tiên hãy đặt bit ngầm, khi giải mã bit ngầm thì không cần phải thêm vào. Tôi đã để lại câu trả lời được đánh dấu là chính xác, vì thông tin đó thực sự hữu ích.Chuẩn hóa Mantissa của C# double
Tôi hiện đang triển khai mã hóa (Quy tắc mã hóa phân biệt) và có vấn đề nhỏ mã hóa giá trị kép.
Vì vậy, tôi có thể nhận ra các dấu hiệu, mũ và mantissa từ một đôi trong C# bằng cách sử dụng:
// get parts
double value = 10.0;
long bits = BitConverter.DoubleToInt64Bits(value);
// Note that the shift is sign-extended, hence the test against -1 not 1
bool negative = (bits < 0);
int exponent = (int)((bits >> 52) & 0x7ffL);
long mantissa = bits & 0xfffffffffffffL;
(sử dụng mã từ here). Các giá trị này có thể được mã hóa và quá trình đảo ngược đơn giản của quy trình sẽ giúp tôi quay lại giá trị gốc ban đầu.
Tuy nhiên, các quy tắc mã hóa DER xác định rằng mantissa nên bình thường:
Trong Rules Encoding Canonical và các quy tắc Encoding sắc bình thường được chỉ định và mantissa (trừ khi nó là 0) cần để được dịch chuyển nhiều lần cho đến khi bit ít quan trọng nhất là 1.
(xem here in section 8.5.6.5).
Việc làm này bằng tay sử dụng:
while ((mantissa & 1) == 0)
{
mantissa >>= 1;
exponent++;
}
sẽ không làm việc, và mang lại cho tôi những giá trị kỳ lạ. (Ngay cả khi sử dụng toàn bộ hàm Jon Skeet được đăng trong liên kết đã nói ở trên).
Tôi dường như thiếu một thứ gì đó ở đây, sẽ dễ nhất nếu tôi lần đầu tiên có thể bình thường hóa mantiassa của đôi và nhận được "bit". Tuy nhiên, tôi cũng không thể hiểu tại sao việc bình thường hóa bằng tay sẽ không hoạt động chính xác.
Nhờ sự giúp đỡ,
Danny
EDIT: Vấn đề làm việc thực tế cho thấy vấn đề của tôi với bình thường mantiss:
static void Main(string[] args)
{
Console.WriteLine(CalculateDouble(GetBits(55.5, false)));
Console.WriteLine(CalculateDouble(GetBits(55.5, true)));
Console.ReadLine();
}
private static double CalculateDouble(Tuple<bool, int, long> bits)
{
double result = 0;
bool isNegative = bits.Item1;
int exponent = bits.Item2;
long significand = bits.Item3;
if (exponent == 2047 && significand != 0)
{
// special case
}
else if (exponent == 2047 && significand == 0)
{
result = isNegative ? double.NegativeInfinity : double.PositiveInfinity;
}
else if (exponent == 0)
{
// special case, subnormal numbers
}
else
{
/* old code, wont work double actualSignificand = significand*Math.Pow(2,
-52) + 1; */
double actualSignificand = significand*Math.Pow(2, -52);
int actualExponent = exponent - 1023;
if (isNegative)
{
result = actualSignificand*Math.Pow(2, actualExponent);
}
else
{
result = -actualSignificand*Math.Pow(2, actualExponent);**strong text**
}
}
return result;
}
private static Tuple<bool, int, long> GetBits(double d, bool normalizeSignificand)
{
// Translate the double into sign, exponent and mantissa.
long bits = BitConverter.DoubleToInt64Bits(d);
// Note that the shift is sign-extended, hence the test against -1 not 1
bool negative = (bits < 0);
int exponent = (int)((bits >> 52) & 0x7ffL);
long significand = bits & 0xfffffffffffffL;
if (significand == 0)
{
return Tuple.Create<bool, int, long>(false, 0, 0);
}
// fix: add implicit bit before normalization
if (exponent != 0)
{
significand = significand | (1L << 52);
}
if (normalizeSignificand)
{
//* Normalize */
while ((significand & 1) == 0)
{
/* i.e., Mantissa is even */
significand >>= 1;
exponent++;
}
}
return Tuple.Create(negative, exponent, significand);
}
Output:
55.5
2.25179981368527E+15
DoubleToInt64Bits() không đưa bạn định nghĩa, nó cung cấp cho bạn giá trị bằng số mũ đã được áp dụng. Mã đó chỉ là sai, vứt nó đi. –
Oh, ok, tôi không biết rằng, tuy nhiên, bạn có một gợi ý làm thế nào tôi có thể có được những gì tôi muốn? Tôi nghĩ rằng bây giờ tôi sẽ thử một công đoàn (tốt, một cấu trúc với bố trí lĩnh vực rõ ràng) – Daniel
Jon Skeet đang hỗ trợ câu trả lời đó, đăng một bình luận ở đó. Một liên minh không hoạt động, các bit này không rơi vào ranh giới byte. –