BigInteger的双不正确舍入
本文关键字:舍入 不正确 BigInteger | 更新日期: 2023-09-27 18:10:56
我正在尝试使用c#中的显式强制转换操作符将BigInteger值转换为双精度值,但没有得到我期望的收敛舍入行为。我找不到关于此操作舍入模式的任何文档,但它与长到双类型转换(这也没有文档记录)不匹配。Bug还是特性?我已经实现了自己的舍入例程来解决这个问题,但我宁愿坚持使用内置的功能。
这是一个测试,通过编写(VS 2012在Windows 7上):
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);
http://referencesource.microsoft.com/#System.Numerics/System/Numerics/BigInteger.cs
这里有实际的源代码,它将向您展示它是如何实现的。
简而言之,它看起来基本上是切和移位,根本没有任何舍入发生。注意,它调用了一个叫做GetApproxParts
的方法。
但是,如果你需要特殊的舍入,它应该很容易在末尾修改。
基本上,只需使用>>
和|
运算符(双精度数尾数有52位)查看BigInteger上的NumBits - 53
rd位(从最高有效到最低有效)。
基本上有三种情况,只有最后一种情况会根据您可能想要采用的不同舍入模式进行不同的处理。
如果第53位没有设置,则不需要舍入。
如果是,检查它后面的位。如果有设置,四舍五入(添加Double.Epsilon)。
如果设置了该值,并且没有设置后面的位,则恰好位于两个有效双精度值的中间。只要是一致的,合理的就行。