【发布时间】:2013-07-24 08:44:24
【问题描述】:
编辑:现在可以工作了,在规范化螳螂时,首先设置隐式位很重要,解码隐式位时不必添加。 我将标记的答案保留为正确,因为那里的信息确实有帮助。
我目前正在实现一种编码(可区分编码规则)并且在编码双精度值时遇到了一点问题。
所以,我可以通过以下方式从 c# 中的双精度数中取出符号、指数和尾数:
// 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 的代码)。 这些值可以被编码,只要简单地反转这个过程,我就能找回原来的双精度值。
但是,DER 编码规则指定尾数应该被归一化:
在 Canonical Encoding Rules 和 Distinguished Encoding Rules 规范化被指定并且尾数(除非它是 0)需要 重复移位,直到最低有效位为 1。
手动使用:
while ((mantissa & 1) == 0)
{
mantissa >>= 1;
exponent++;
}
不起作用,并给了我奇怪的值。 (即使使用上述链接中发布的整个功能 Jon Skeet)。
我似乎在这里遗漏了一些东西,如果我首先可以规范化双倍的 mantiassa 并获得“位”,那将是最简单的。但是,我也无法真正理解为什么手动标准化不能正常工作。
感谢您的帮助,
丹尼
编辑:显示螳螂规范化问题的实际工作问题:
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() 不会为您提供尾数,它会为您提供已应用指数的值。那个代码是错误的,扔掉它。
-
哦,好吧,我不知道,但是,你有什么建议可以让我得到我想要的吗?我想我现在尝试一个联合(嗯,一个具有显式字段布局的结构)
-
Jon Skeet 支持该答案,请在此处发表评论。联合不起作用,这些位不会落在字节边界上。
-
我看到这些位不属于字节边界,但对于 doubleToInt64Bits 部分,我认为我可以在同一个结构中放置一个 long 和一个 double 。好吧,我照你说的做了,并在那里发表了评论。
-
我恐怕对区分编码规则一无所知...
标签: c# encoding floating-point