所以我想写一个方法: 142^23 (mod 187),使用任何计算器我得到结果65,但是用这段代码:double number = Math.Pow(142, 23) % 187我得到了53的结果。为什么,我在这里做错什么了?
发布于 2018-03-23 18:29:03
Math.Pow(142, 23)太大了,无法精确地用双人表示。所以你的模数是在有耗的计算上做的。
这将给出正确的答案:
BigInteger.ModPow(142, 23, 187);BigInteger可以在System.Numerics命名空间和程序集中找到。
如果您想要的话,您也可以自己高效地实现这一点,对于您在问题中使用的大小的整数来说。
private static int ModPow(int basenum, int exponent, int modulus)
{
if (modulus == 1)
{
return 0;
}
int result = 1;
for (var i = 0; i < exponent; i++)
{
result = (result * basenum) % modulus;
}
return result;
}BigInteger用二进制指数做了一些更聪明的事情,这将对真正庞大的数字更好地工作。
发布于 2018-03-23 19:34:44
如果我们使用BigInteger来计算指数的全部结果:
var bi = BigInteger.Pow(142, 23);
Debug.WriteLine(bi);我们得到了一个非常大的数字:
31814999504641997296916177121902819369397243609088
or
3.1814999504642E+49如果我们然后将该值转换为double,则会导致精度下降,然后返回到BigInteger
var d = (double) bi;
bi = new BigInteger(d);
Debug.WriteLine(bi);我们得到:
31814999504641997296916177121902819369397243609088 -- BigInteger
31814999504641993108158684988768059669621048868864 -- BigInteger -> double -> BigInteger
^ oh no mah precision在十六进制中,精度损失更为明显:
15C4 C9EB 18CD 25CE 858D 6C2D C3E5 D319 BC9B 8000 00
15C4 C9EB 18CD 2500 0000 0000 0000 0000 0000 0000 00
^ oh no mah precision您会注意到,精度损失发生在十七个小数位,或者十四个十六进制数字。
为什么?
is stored using IEEE-754 encoding
Significand or mantissa: 0-51
Exponent: 52-62
Sign (0 = Positive, 1 = Negative) 63这里的关键是尾数的52位。我们的14位十六进制数字是56位,接近52位限制.我们怎么解释这个4位差异呢?
(我想我在下面的解释中犯了一个错误。如果有人能指出,我将不胜感激)
最后一个不变的十六进制数字是C,或二进制的1100;因为最后两个位是零,所以我们的数字是用54位编码的,而不是56位。所以,这实际上是一个2位的差异。
我们如何解释最后两部分呢?这是由于如何确定IEEE-754的分数分量。我已经很久没有这样做了,所以我将把它作为一个练习留给读者:
https://stackoverflow.com/questions/49456119
复制相似问题