C# C、 模运算给出的结果与计算器不同

C# C、 模运算给出的结果与计算器不同,c#,math,mod,C#,Math,Mod,所以我想写这个方法:142^23 mod 187,使用任何计算器我都会得到结果65,但是用这段代码: 双倍数字=Math.Pow142,23%187 我的成绩是53分。为什么会这样,我做错了什么 Math.Pow142,23太大,无法用双精度表示。所以你的模数是在有损计算的基础上计算出来的 这将给出正确的答案: BigInteger.ModPow(142, 23, 187); 可以在System.Numerics命名空间和程序集中找到BigInteger 如果您想对您在问题中使用的整数这样做,

所以我想写这个方法:142^23 mod 187,使用任何计算器我都会得到结果65,但是用这段代码: 双倍数字=Math.Pow142,23%187 我的成绩是53分。为什么会这样,我做错了什么

Math.Pow142,23太大,无法用双精度表示。所以你的模数是在有损计算的基础上计算出来的

这将给出正确的答案:

BigInteger.ModPow(142, 23, 187);
可以在System.Numerics命名空间和程序集中找到BigInteger

如果您想对您在问题中使用的整数这样做,您也可以自己高效地实现它

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在二进制幂运算方面做得更聪明,它在处理真正巨大的数字时会更好。

Math.Pow142,23太大,无法用双精度表示。所以你的模数是在有损计算的基础上计算出来的

这将给出正确的答案:

BigInteger.ModPow(142, 23, 187);
可以在System.Numerics命名空间和程序集中找到BigInteger

如果您想对您在问题中使用的整数这样做,您也可以自己高效地实现它

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通过二进制指数运算做了一些更聪明的事情,这将更好地处理真正巨大的数字。

如果我们使用BigInteger计算指数运算的完整结果:

var bi = BigInteger.Pow(142, 23);
Debug.WriteLine(bi);
我们得到了这个非常大的数字:

31814999504641997296916177121902819369397243609088
or
3.1814999504642E+49
如果我们随后将该值转换为double,导致精度损失,然后返回到BigInteger:

我们得到:

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
您会注意到精度损失发生在第17位十进制数字或第14位十六进制数字

为什么?

:

这里的关键是尾数的52位。我们的14位十六进制数字是56位,接近52位的限制。我们如何解释4位差异

我想我在下面的解释中犯了一个错误。如果有人能指出这一点,我将不胜感激

最后一个不变的十六进制数字是C,或二进制中的1100;因为最后两位是零,所以我们的数字编码为54位,而不是56位。所以,它实际上是一个2位的差异

我们如何解释最后两位呢?这是由于IEEE-754的分数分量是如何确定的。我已经很久没有这样做了,所以我将把它留给读者作为练习:

如果我们使用BigInteger来计算指数的完整结果:

var bi = BigInteger.Pow(142, 23);
Debug.WriteLine(bi);
我们得到了这个非常大的数字:

31814999504641997296916177121902819369397243609088
or
3.1814999504642E+49
如果我们随后将该值转换为double,导致精度损失,然后返回到BigInteger:

我们得到:

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
您会注意到精度损失发生在第17位十进制数字或第14位十六进制数字

为什么?

:

这里的关键是尾数的52位。我们的14位十六进制数字是56位,接近52位的限制。我们如何解释4位差异

我想我在下面的解释中犯了一个错误。如果有人能指出这一点,我将不胜感激

最后一个不变的十六进制数字是C,或二进制中的1100;因为最后两位是零,所以我们的数字编码为54位,而不是56位。所以,它实际上是一个2位的差异


我们如何解释最后两位呢?这是由于IEEE-754的分数分量是如何确定的。我已经很久没有这样做了,所以我将把它作为练习留给读者:

我们在这里谈论的是什么计算器?@Steve any calculator!BigInteger.ModPow142,23187给我65。我怀疑这个数字太大了,所以double不得不牺牲精度。我不知道如何证明这一点。我们在这里谈论的是什么计算器?@Steve any calculator!BigInteger.ModPow142,23187给我65。我怀疑这个数字太大了,所以double不得不牺牲精度。但我不知道如何证明这一点。@vcsjones我无法完全解释我的评论中精度的损失,所以我一直在执行一项任务。这是一个有趣而又富有挑战性的问题。我仍在研究最后两位。我很确定我在某处犯了一个错误。@vcsjones我无法完全解释我的评论中的精度损失,所以我一直在执行任务。这是一个有趣而又富有挑战性的问题。我还在做最后两部分。我很确定我在什么地方犯了个错误。