C#中的Mod:它返回一个错误的值

时间:2014-11-11 08:25:31

标签: c# math encryption rsa

好的,这是我的代码:

       int a, b, c, d;
        double v1, v2, v3, vf, val;

        a = 110;
        b = 13;
        c = 437;
        d = 61;

        v1 = Convert.ToDouble(a);
        v2 = Convert.ToDouble(b);
        v3 = Convert.ToDouble(d);

        val = Math.Pow(v1, v2);
        val = val % c;

        Console.WriteLine("O valor do primeiro MOD é: {0}", val);

        vf = Math.Pow(val, v3);
        vf = vf % c;

        Console.WriteLine("O valor final é: {0}", vf);
        Console.ReadKey();

这就是事情,如果我使用计算器这样做,我会得到这些结果:

110 ^ 13 = 345227121439310000000000000

345227121439310000000000000 437 = 48

48 ^ 61 = 3,5951372914138399900210185557119e + 102

3,5951372914138399900210185557119e + 102 437 = 110

但是,使用我的代码我得到了这些结果:

http://imageshack.com/a/img537/1309/7l42tc.jpg

对于那些看不到图像的人,结果如下:

val = 337 vf = 6

3 个答案:

答案 0 :(得分:3)

使用64位双精度,110^1348^61都不能完全表示。数据类型没有足够的精度来准确表示这些值。因为您无法准确表示操作数,所以实际上您执行的算术与您要执行的操作不同。一旦你无法代表原始的操作数,就没有恢复的希望。

您需要使用具有足够精度的类型。例如,System.Numerics.BigInteger

答案 1 :(得分:2)

Double远远不够精确。双倍是precise to 16 digits。您的值分别为26和102位。无法表示的数字会丢失,导致精度损失。

你应该使用某种bigint库:

答案 2 :(得分:1)

它使用双精度工作的原因是因为双精度数据类型没有足够的精度。像110^13这样的大数字不能完全表示为双重数字 - 它们会丢失很多有效数字。

解决方案是使用可以表示非常大的整数的类型来计算它。

以下是使用BigInteger

进行操作的方法
BigInteger a = new BigInteger(110);
BigInteger b = new BigInteger(13);
BigInteger c = new BigInteger(437);

BigInteger val = BigInteger.ModPow(a, b, c);

请注意具体方法ModPow()如何将提升与功率和模数相结合。

另请注意,您可以使用隐式构造函数将int转换为BigInteger,从而将上述代码简化为:

BigInteger val = BigInteger.ModPow(110, 13, 437);