C#中的模块化立方体

时间:2010-01-12 14:01:45

标签: c# algorithm

我很难解决这个问题:

  

对于正数n,定义C(n)   作为整数x,for   哪个1< x< n和x ^ 3 = 1 mod n。

     

当n = 91时,有8个可能的值   对于x,即:9,16,22,29,53,74,   79,81。因此,C(91)= 8。

     

找出正数的总和   n <= 10 ^ 11,其中C(n)= 242。

我的代码:

double intCount2 = 91;
double intHolder = 0;

for (int i = 0; i <= intCount2; i++)
{
    if ((Math.Pow(i, 3) - 1) % intCount2 == 0)
    {
        if ((Math.Pow(i, 3) - 1) != 0)
        {
            Console.WriteLine(i);
            intHolder += i;
        }
    }
}
Console.WriteLine("Answer = " + intHolder);
Console.ReadLine();

这适用于91但是当我输入任意数量很多的0时,它给了我很多答案我知道是假的。我认为这是因为它非常接近于0,它只是舍入到0.有什么方法可以看出某些东西是否正好是0?或者我的逻辑错了?

我知道我需要进行一些优化以获得及时的答案,但我只是想让它产生正确答案。

5 个答案:

答案 0 :(得分:13)

让我将你的问题概括为两个问题:

1)这个程序有什么特别的错误?

2)如何确定程序中的问题所在?

其他人已经回答了第一部分,但总结一下:

问题#1:Math.Pow使用双精度浮点数,它只精确到大约15位小数。它们不适合处理需要完美准确性的问题,涉及大整数。如果你尝试计算1000000000000000000 - 1,在双打中,你将得到1000000000000000000,这是15个小数位的准确答案;这就是我们所能保证的。如果你需要一个完全准确的答案来处理大数,那么使用long来获得低于约100亿亿的结果,或者使用System.Numerics中的大整数数学类,它将随框架的下一个版本一起提供。

问题2:有更有效的方法来计算模块化指数,这些方法不涉及产生大量数字;使用它们。

然而,我们在这里得到的是“给人一条鱼”的情况。更好的是教你如何钓鱼;学习如何使用调试器调试程序。

如果我必须调试这个程序,我要做的第一件事就是重写它,以便沿途的每一步都存储在一个局部变量中:

double intCount2 = 91; 
double intHolder = 0; 

for (int i = 0; i <= intCount2; i++) 
{ 
    double cube = Math.Pow(i, 3) - 1;
    double remainder = cube % intCount2;
    if (remainder == 0) 
    { 
        if (cube != 0) 
        { 
            Console.WriteLine(i); 
            intHolder += i; 
        } 
    } 
} 

现在在调试器中逐步执行它,并举例说明答案是错误的,并查找违反假设的地方。如果你这样做,你会很快发现1000000立方减-1不是99999999999999999,而是1000000000000000000。

这样的建议#1:编写代码,以便在调试器中轻松完成,并检查每个步骤,寻找看似错误的代码。

建议#2:注意安静的唠叨疑惑。当某些东西看起来很狡猾或者你有点不理解时,请进行调查直到你理解它为止。

答案 1 :(得分:3)

维基百科有一篇关于Modular exponentiation的文章,你可以找到它的信息。 IIRC,Python内置它.C#没有,所以你需要自己实现它。

答案 2 :(得分:3)

不要使用n计算模Math.Pow的幂;您可能会在其他可能的问题中遇到溢出问题。相反,你应该从第一原则计算它们。因此,要计算整数in的立方体,首先将in减少到某个整数j,以便i是全等的以j为模n0 <= j < n。然后迭代乘以j并在每次乘法后减少模n;要计算一个多维数据集,您将执行此步骤两次。当然,这是本机方法,但您可以通过使用exponentiation by squaring遵循经典的取幂算法来提高效率。

另外,就效率而言,我注意到你不必要地计算Math.Pow(i, 3) - 1两次。因此,至少,替换

if ((Math.Pow(i, 3) - 1) % intCount2 == 0) {
    if ((Math.Pow(i, 3) - 1) != 0) {
        Console.WriteLine(i);
        intHolder += i;
    }
}

int cubed = Math.Pow(i, 3) - 1;
if((cubed % intCount2 == 0) && (cubed != 0)) {
    Console.WriteLine(i); 
    intHolder += i;
}

答案 3 :(得分:0)

嗯,有些东西丢失或者错字......

“intHolder1”应该大概是“intHolder”而intCount2 = 91导致8增量行应该是: -

intHolder ++;

答案 4 :(得分:0)

我没有解决您的问题,但这只是一条建议:

  • 不要将浮点数用于仅涉及整数的计算......类型intInt32)显然不足以满足您的需求,但longInt64)应该足够了:您需要操作的最大数字是(10 ^ 11 - 1) ^ 3,小于10 ^ 14,这肯定小于Int64.MaxValue。好处:

    • 使用64位整数进行所有计算,这在64位处理器上非常有效
    • 您计算的所有结果都是准确的,因为由于双重内部表示而没有近似值


  • 不要使用Math.Pow计算整数的立方体... x*x*x同样简单,效率更高,因为它不需要转换为/来自double。无论如何,我不是很擅长数学,但你可能不需要计算 x ^ 3 ...检查其他答案中关于模幂运算的链接