BigInteger加倍不正确的舍入

时间:2014-07-01 16:31:31

标签: c# rounding biginteger

我正在尝试使用C#中的显式强制转换运算符将BigInteger值转换为双精度值,但是没有得到我预期的收敛舍入行为。我找不到关于此操作的舍入模式的任何文档,但它与long to double cast(也未记录)的文档不匹配。错误或功能?我已经实现了自己的舍入程序来解决它,但宁可坚持使用内置功能。<​​/ p>

这是一个经过编写的测试(Windows 7上的VS 2012):

BigInteger roundMeDown = BigInteger.Pow(2, 53) + 1;
double expectedRoundedDown = Math.Pow(2, 53);

BigInteger roundMeUp = BigInteger.Pow(2, 53) + 3;
double expectedRoundedUp = Math.Pow(2, 53) + 4;
double actualResult = Math.Pow(2, 53) + 2;

Assert.AreEqual(expectedRoundedDown, (double)roundMeDown);

Assert.AreNotEqual(expectedRoundedUp, (double)roundMeUp);
Assert.AreEqual(actualResult, (double)roundMeUp);

1 个答案:

答案 0 :(得分:1)

http://referencesource.microsoft.com/#System.Numerics/System/Numerics/BigInteger.cs

有实际的源代码,它会告诉你它是如何做到的。

简而言之,它看起来基本上是在切换和移位,而根本没有任何四舍五入。请注意,它调用了一个名为GetApproxParts的方法。

但是,如果你需要特殊的舍入,最后应该很容易入侵。

基本上,只需使用NumBits - 53>>运算符查看BigInteger上的| rd位(从最重要到最不重要)(双尾数在尾数中有52位)。

基本上有三种情况,根据您可能想要使用的不同舍入模式,只有最后一种处理方式不同。

如果未设置第53位,则无需舍入。

如果是,请检查后面的位。如果设置了任何一个,则向上舍入(添加Double.Epsilon)。

如果已设置且设置后没有位,则正好位于两个有效双精度值的中间。做任何合理的事情,只要它是一致的。