C#double的尾数正规化

C#double的尾数正规化,c#,encoding,floating-point,C#,Encoding,Floating Point,编辑:现在开始工作,在规范化mantiss时,首先设置隐式位很重要,解码隐式位时,不必添加。 我留下了正确的答案,因为那里的信息确实有用 我目前正在实现一种编码(区分编码规则),在编码双值时有一点问题 因此,我可以通过使用以下公式从c#中的双精度中得出符号、指数和尾数: // get parts double value = 10.0; long bits = BitConverter.DoubleToInt64Bits(value); // Note that the shift is

编辑:现在开始工作,在规范化mantiss时,首先设置隐式位很重要,解码隐式位时,不必添加。 我留下了正确的答案,因为那里的信息确实有用

我目前正在实现一种编码(区分编码规则),在编码双值时有一点问题

因此,我可以通过使用以下公式从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;
不会工作,给我奇怪的价值观。(即使使用上述链接中发布的Jon Skeet的整个功能)

我似乎在这里遗漏了一些东西,如果我能首先将双精度的Mantiasa标准化并得到“位”,这将是最容易的。然而,我也不明白为什么手工规范化不能正常工作

谢谢你的帮助

丹尼

编辑:实际工作问题显示我的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
static void Main(字符串[]args)
{
Console.WriteLine(CalculateDouble(GetBits(55.5,false));
Console.WriteLine(CalculateDouble(GetBits(55.5,true));
Console.ReadLine();
}
专用静态双计算双倍(元组位)
{
双结果=0;
bool isNegative=bits.Item1;
int指数=位.Item2;
长有效位=位。项目3;
if(指数=2047&&magnifind!=0)
{
//特例
}
else if(指数=2047&&有效位=0)
{
结果=为阴性?双重。阴性证实:双重。阳性证实;
}
如果(指数=0),则为else
{
//特例,次正常数
}
其他的
{
/*旧代码,无法使用双实际值signific并=有效位*Math.Pow(2,
-52) + 1; */
双实际值与=有效位*数学功率(2,-52);
int ActualComponent=指数-1023;
如果(为负)
{
结果=实际重要性和*数学功率(2,实际成分);
}
其他的
{
结果=-actualsignific和*Math.Pow(2,actualComponent);**强文本**
}
}
返回结果;
}
私有静态元组GetBits(双d,布尔规范化significand)
{
//将双精度转换为符号、指数和尾数。
长位=位转换器。双字节64位(d);
//注意,移位是符号扩展的,因此针对-1而不是1进行测试
布尔负=(位<0);
int指数=(int)((位>>52)和0x7ffL);
长有效位=位&0xFFFFFFFFFL;
如果(有效位==0)
{
返回Tuple.Create(false,0,0);
}
//修正:在规范化之前添加隐式位
如果(指数!=0)
{
有效位=有效位|(1L>=1;
指数++;
}
}
返回Tuple.Create(负数、指数、有效位);
}
输出:
55.5
2.25179981368527E+15

当您使用
位转换器.doubleToInt64位
时,它会为您提供已编码为IEEE 754格式的
值。这意味着有效位使用隐式前导位进行编码。(“有效位”是浮点值的分数部分的首选术语,在IEEE 754中使用。有效位是线性的。尾数是对数。“尾数”起源于人们不得不使用对数、纸张和函数表进行粗略计算的时代。)要恢复未编码的有效位,必须恢复隐式位

这并不难。分离符号位、编码指数(作为整数)和编码有效位(作为整数)后,对于64位二进制浮点:

  • 如果编码的指数为其最大值(2047),且编码的有效位为非零,则该值为NaN。有效位中包含有关NaN是否为信令的附加信息以及其他用户或实现定义的信息
  • 如果编码指数为其最大值,编码有效位为零,则该值为无穷大(+或–根据符号)
  • 如果编码指数为零,则隐式位为零,实际有效位为编码有效位乘以2–52,实际指数为1减去偏差(1023)(so–1022)
  • 否则,隐式位为1,实际有效位为编码有效位,先乘以2–52,然后加上1,实际指数为编码指数减去偏差(1023)
(如果要处理整数,而有效位没有分数,可以省略2–52的乘法,将–52添加到指数。在最后一种情况下,有效位将添加到252而不是1。)

有一种替代方法可以避免
位转换器
和IEEE-754编码。如果可以从C#调用
frexp
例程,它将以数学方式返回分数和指数,而不是作为编码。首先,分别处理零、无穷和NaN。然后使用:

int exponent;
double fraction = frexp(value, &exponent);
这将
分数
设置为一个大小为[½,1]和
指数
的值,使得
分数
•2
指数
等于
(请注意,
分数
仍然有符号;您可能需要将其分开,然后使用绝对值。)

此时,您可以根据需要缩放分数(并相应调整指数)。要将其缩放为奇数整数,您可以重复将其乘以2,直到它没有分数部分。

DoubleToInt64位()不会得到尾数,它会给你已经应用了指数的值。那代码是错误的,扔掉它。哦
int exponent;
double fraction = frexp(value, &exponent);