米勒拉宾Primality测试

时间:2011-10-22 16:12:02

标签: c#

我用C sharp编写了一个Miller Rabin素数测试,但是每次输入都会返回false。

以下是代码:

    static Boolean MilRab(UInt64 n)
    {
        UInt64[] ar = new UInt64[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 };
        for (int i = 0; i < 10; i++)
        {
            if (Tanu(ar[i], n) == true) return false;
        }
        return true;
    }//MilRab

    static Boolean Tanu(UInt64 a, UInt64 n)
    {
        UInt64 b = n - 1;
        UInt64 d = 1;
        UInt64 x;
        Int16 i;
        for (i = 63; i >= 0; i--) if (((b >> i) & 1) == 1) break;

        for (;i>=0;i--)
        {
            x = d;
            d = ((d * d) % n);
            if (d == 1 && x != 1 && x != n - 1) return true;
            if (b>>i == 1) d = (d * a) % n;
        }
        if (d != 1) return true;
      return false;
    }//Tanu

您认为问题是什么?我花了一天时间进行调试,这让我很疯狂。谢谢。

2 个答案:

答案 0 :(得分:3)

答案 1 :(得分:2)

正如阿米尔所说,

http://rosettacode.org/wiki/Miller-Rabin_primality_test#C.23

有解决方案。但是..我试过它,即使对于非常小的输入值,如79,它也会给出错误的结果(79是素数,但是反复出现而不是素数)。原因是功率溢出(例如11 ^ 78类似于1E + 81,无法用32或64位整数表示)。

所以这里

public static class RabinMiller
{
    public static bool IsPrime(int n, int k)
    {
        if(n < 2)
        {
            return false;
        }
        if(n != 2 && n % 2 == 0)
        {
            return false;
        }
        int s = n - 1;
        while(s % 2 == 0)
        {
            s >>= 1;
        }
        Random r = new Random();
        for (int i = 0; i < k; i++)
        {
            double a = r.Next((int)n - 1) + 1;
            int temp = s;
            int mod = (int)Math.Pow(a, (double)temp) % n;
            while(temp != n - 1 && mod != 1 && mod != n - 1)
            {
                mod = (mod * mod) % n;
                temp = temp * 2;
            }
            if(mod != n - 1 && temp % 2 == 0)
            {
                return false;
            }
        }
        return true;
    }
}

你应该添加一个功能

    static int ModuloPower(int a, int b, int n)
    {
        // return (a^b)%n
        int res = 1;
        for (int i = 0; i < b; ++i)
            res = (res * a) % n;
        return res;
    }

并将power / modulo行更改为

    int mod = ModuloPower(a, temp, n); // (int)Math.Pow(a, (double)temp) % n;

这当然可以再次优化..请参阅rosettacode网站上其他语言的代码示例,以获得更快速计算功率/模数的更聪明方法。

(我尝试在那里编辑代码,但必须注册,所以我在这里发帖。)