尾数标准化C#double

尾数标准化C#double,第1张

概述编辑:现在让它工作,同时规范化mantiss,首先设置隐含位是很重要的,当解码隐含位然后不必添加. 我将标记的答案保留为正确,因为那里的信息确实有帮助. 我目前正在实现编码(专有编码规则),并且编码双值时会有轻微问题. 所以,我可以通过使用以下方式从c#中的double中取出符号,指数和尾数: // get parts double value = 10.0; long bits = BitC 编辑:现在让它工作,同时规范化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,直到它没有小数部分.

总结

以上是内存溢出为你收集整理的尾数标准化C#double全部内容,希望文章能够帮你解决尾数标准化C#double所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1244537.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-07
下一篇 2022-06-07

发表评论

登录后才能评论

评论列表(0条)

保存