在一个非常高性能的应用程序中,我们发现CPU计算长算术的速度比使用doubles快得多。然而,在我们的系统中,我们被确定永远不需要超过9位小数的精度。因此,我们对所有精度为9点的浮点算术都使用长整型。
然而,在系统的某些部分,由于使用doubles的可读性,它更方便。因此,我们必须将采用9位小数的长值转换为双精度。
我们发现,简单地将长度除以10的9次方或乘以1除以10的9次方给出了不精确的双精度表示。
为了解决这个问题,我们使用Math.Round(value,9)来给出精确的值。
然而,Math.Round()的性能慢得可怕。
所以我们目前的想法是将尾数和指数直接转换为双精度的二进制格式,因为这样就不需要舍入了。
我们已经在网上学习了如何检查双精度数的位来获得尾数和指数,但是要找出如何反转尾数和指数并使用位来构造双精度数是令人困惑的。
有什么建议吗?
[Test]
public unsafe void ChangeBitsInDouble()
{
var original = 1.0D;
long bits;
double* dptr = &original;
//bits = *(long*) dptr;
bits = BitConverter.DoubleToInt64Bits(original);
var negative = (bits < 0);
var exponent = (int) ((bits >> 52) & 0x7ffL);
var mantissa = bits & 0xfffffffffffffL;
if( exponent == 0)
{
exponent++;
}
else
{
mantissa = mantissa | (1L << 52);
}
exponent -= 1075;
if( mantissa == 0)
{
return;
}
while ((mantissa & 1) == 0)
{
mantissa >>= 1;
exponent++;
}
Console.WriteLine("Mantissa " + mantissa + ", exponent " + exponent);
}发布于 2012-01-19 21:43:40
不应使用10^9的比例因子,而应使用2^30。
发布于 2012-01-19 23:27:50
正如您已经意识到的那样,根据另一个答案,doubles是通过浮点二进制而不是浮点十进制工作的,因此最初的方法不起作用。
也不清楚它是否可以使用一个刻意简化的公式,因为它不清楚您需要的最大范围是多少,因此舍入是不可避免的。
快速而精确地完成这一任务的问题已经得到了充分的研究,并且经常得到CPU指令的支持。击败内置转换的唯一机会是:
除非您使用的值范围非常有限,否则在双精度IEEE754和长整型之间进行转换的可能性会变得越来越小。
如果你不得不涵盖IEEE754涵盖的大多数情况,甚至是相当大的一部分,那么你最终会让事情变得更慢。
我建议要么保留现有的,要么移动到double更方便的情况下,无论如何,尽管不方便,但长期坚持,或者如果必要的话,使用decimal。您可以使用以下命令从long轻松创建decimal:
private static decimal DivideByBillion (long l)
{
if(l >= 0)
return new decimal((int)(l & 0xFFFFFFFF), (int)(uint)(l >> 32), 0, false, 9);
l = -l;
return new decimal((int)(l & 0xFFFFFFFF), (int)(uint)(l >> 32), 0, true, 9);
}现在,在算术中使用decimal比使用double慢得多(正是因为它实现了一种与您在开头问题中类似的方法,但具有不同的指数和更大的尾数)。但是,如果你只需要一个方便的方法来获得一个值来显示或呈现为字符串,那么手动转换到decimal比手动转换到double更有优势,所以它值得一看。
https://stackoverflow.com/questions/8926793
复制相似问题