編集:仮数を正規化する際に、最初に暗黙のビットを設定することが重要です。暗黙のビットをデコードするときは、追加する必要はありません。そこにある情報が本当に役に立ったので、マークされた答えを正しいままにしました。
現在、エンコーディング (識別エンコーディング規則) を実装していますが、double 値のエンコーディングに若干の問題があります。
したがって、次を使用して、C# の double から符号、指数、および仮数を取得できます。
// 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;
( hereのコードを使用)。これらの値はエンコードすることができ、プロセスを逆にするだけで元の double が返されます。
ただし、DER エンコーディング規則では、仮数を正規化する必要があると指定されています。
Canonical Encoding Rules と Distinguished Encoding Rules では正規化が指定されており、最下位ビットが 1 になるまで仮数 (0 でない限り) を繰り返しシフトする必要があります。
(セクション 8.5.6.5 のこちらを参照してください)。
以下を使用して手動でこれを行います。
while ((mantissa & 1) == 0)
{
mantissa >>= 1;
exponent++;
}
動作せず、奇妙な値が返されます。(前述のリンクに投稿されたJon Skeetの機能全体を使用する場合でも)。
ここで何かが欠けているようです。最初に double の仮数を正規化し、「ビット」を取得できれば最も簡単です。ただし、手作業による正規化が正しく機能しない理由もよくわかりません。
助けてくれてありがとう、
ダニー
編集:カマキリの正規化に関する私の問題を示す実際の作業上の問題:
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