加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

尾数标准化C#double

发布时间:2020-12-16 05:05:40 所属栏目:百科 来源:网络整理
导读:编辑:现在让它工作,同时规范化mantiss,首先设置隐含位是很重要的,当解码隐含位然后不必添加. 我将标记的答案保留为正确,因为那里的信息确实有帮助. 我目前正在实现编码(专有编码规则),并且编码双值时会有轻微问题. 所以,我可以通过使用以下方式从c#中的doub
编辑:现在让它工作,同时规范化mantiss,首先设置隐含位是很重要的,当解码隐含位然后不必添加.
我将标记的答案保留为正确,因为那里的信息确实有帮助.

我目前正在实现编码(专有编码规则),并且编码双值时会有轻微问题.

所以,我可以通过使用以下方式从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的代码).
这些值可以编码,过程的简单反转将使我恢复原来的双倍.

但是,DER编码规则指定应该对尾数进行规范化:

In the
Canonical Encoding Rules and the Distinguished Encoding Rules normalization is specified and the mantissa (unless it is 0) needs
to be repeatedly shifted until the least significant bit is a 1.

(见here in section 8.5.6.5).

手动执行此操作:

while ((mantissa & 1) == 0)
 {
     mantissa >>= 1;
     exponent++;
 }

不行,并给我奇怪的价值观. (即使使用Jon Skeet在上述链接中发布的整个功能).

我似乎在这里遗漏了一些东西,如果我第一次能够规范化双重的mantiassa并得到“位”,那将是最简单的.但是,我也无法真正理解为什么手动标准化将无法正常工作.

谢谢你的帮助,

丹尼

编辑:实际工作问题显示我的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,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,long>(false,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

解决方法

当您使用BitConverter.DoubleToInt64Bits时,它会为您提供已经以IEEE 754格式编码的双精度值.这意味着有效数据用隐式前导位编码. (“有效”是浮点值的小数部分的首选术语,用于IEEE 754.有效数是线性的.尾数是对数的.“尾数”源于人们不得不使用对数和纸的日子.和粗略计算的函数表.)要恢复未编码的有效数,您必须恢复隐含位.

这并不难.一旦你将符号位,编码的指数(作为整数)和编码的有效数字(作为整数)分开,那么,对于64位二进制浮点:

>如果编码的指数是其最大值(2047)且编码的有效数字不为零,则该值为NaN.关于NaN是否发信号以及其他用户或实现定义的信息,还有关于有效性的附加信息.
>如果编码的指数是其最大值且编码的有效数为零,则该值为无穷大(或 – 根据符号).
>如果编码指数为零,则隐含位为零,实际有效位数为编码有效数乘以2-52,实际指数为1减去偏差(1023)(所以-1022).
>否则,隐含位为1,实际有效位数是编码的有效位数,首先乘以2-52然后加到1,实际指数是编码指数减去偏差(1023).

(如果你想使用整数而不是有效数的分数,你可以省略乘法2-52并将-52加到指数中.在最后一种情况下,有效数加到252而不是1. )

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

int exponent;
double fraction = frexp(value,&exponent);

这将分数设置为幅度为[?,1]且指数的值,使得分数?2指数等于值. (注意,分数仍然有符号;您可能希望将其分开并使用绝对值.)

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读