C#double的尾数正规化
编辑:现在开始工作,在规范化mantiss时,首先设置隐式位很重要,解码隐式位时,不必添加。 我留下了正确的答案,因为那里的信息确实有用 我目前正在实现一种编码(区分编码规则),在编码双值时有一点问题 因此,我可以通过使用以下公式从c#中的双精度中得出符号、指数和尾数: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
// 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)
位转换器
和IEEE-754编码。如果可以从C#调用frexp
例程,它将以数学方式返回分数和指数,而不是作为编码。首先,分别处理零、无穷和NaN。然后使用:
int exponent;
double fraction = frexp(value, &exponent);
这将分数
设置为一个大小为[½,1]和指数
的值,使得分数
•2指数
等于值
(请注意,分数
仍然有符号;您可能需要将其分开,然后使用绝对值。)
此时,您可以根据需要缩放分数(并相应调整指数)。要将其缩放为奇数整数,您可以重复将其乘以2,直到它没有分数部分。DoubleToInt64位()不会得到尾数,它会给你已经应用了指数的值。那代码是错误的,扔掉它。哦
int exponent;
double fraction = frexp(value, &exponent);