用Monte Carlo算法实现素数判定
发布日期:2021-05-20 07:54:58 浏览次数:20 分类:精选文章

本文共 4428 字,大约阅读时间需要 14 分钟。

#Monte Carlo算法与素数判定的改进

##问题描述判定一个给定的整数是否为素数一直是数论领域中的重要问题。传统的尝试法和辗转相除法虽然可行,但对于大数的判定效率较低。而Monte Carlo算法提供了一种概率性方法,能够显著提升判定效率。

##Monte Carlo算法###1.预备知识费马小定理是Monte Carlo算法的理论基础。费马小定理指出:!代码描述图片!其逆否命题为:!代码描述图片!

传统地,人们曾试图利用费马小定理直接判定整数是否为素数。以下代码展示了一个基于费马小定理的素数判定函数:

//利用费马小定理(正确的概率较低)void Fermat(int n) {    bool flag = true;    srand((unsigned)time(0));    int a = uniform(1, n); // [1, n-1]    if(Pow(a, n - 1) % n != 1)        flag = false;    Print(flag, n); // flag = true未必是素数}

###2.对Fermat测试的改进为了解决费马小定理的局限性,现代算法采用更为严格的测试方法。改进后的算法基于以下理论:

n是一个大于4的奇整数,满足n − 1 = 2^s * t,其中t为奇数。当且仅当参数a满足以下条件之一时,n为伪素数:

  • a属于[2, n − 2],并且a^t % n == 1
  • 存在整数i属于[0, s − 1],且a^(2^i * t) % n == n − 1
  • 代码如下:

    //对Fermat的改进//判定a是否为n素性的强伪证据bool Btest(int a, int n) {    int s = 0, t = n - 1;    do {        s++;        t /= 2;    } while (t % 2 != 1);    int x = 1;    while (t--) {        x = (x * (a % n)) % n;    }    if (x == 1 || x == n - 1)        return true;    for (int i = 1; i < s; i++) {        x = (x * x) % n;        if (x == n - 1)            return true;    }    return false; //一定是合数}

    Mill-Rab测试函数:

    bool MillRab(int n) {    int a = uniform(2, n - 1); // [2, n-2]    return Btest(a, n); // 测试n是否为强伪素数}

    为了降低误判概率,需要多次调用Mill-Rab测试函数,并统计测试结果。以下函数用于重复测试并减少误判:

    bool RepeatMillRab(int n, int k) {    for (int i = 1; i <= k; i++) {        if (MillRab(n) == false)            return false;    }    return true;}

    泛型素数判定函数:

    void PrintPrimes() {    int pn = 2, count = 2;    printf("2 3 ");    int n = 5;    do {        if (RepeatMillRab(n, 10)) { // 当k=10时,误判概率低于百万分之一            int/method TraditionalMethod(n):                int upper = floor(sqrt(n));                for (int i = 2; i <= upper; i++) {                    if (n % i == 0)                        return false;                }            return true;        }        pn++;        count++;        printf("%d", n);        if (count % 20 == 0)            printf("\n");        else            printf(" ");    } while (n < 10000);    printf("误判个数:%d", count - pn);    double correct = (double)(pn) / count * 100;    printf("\n正确比例:%f%%\n", correct);}

    ##完全代码及运行结果完整代码如下:

    #include 
    #include
    #include
    #include
    using namespace std;typedef long long LL;void Print(bool flag, int n) { if (flag) printf("%d is a prime.\n", n); else printf("%d is not a prime.\n", n);}void TraditionalPrime(int n) { bool flag = true; int upper = floor(sqrt(n)); for (int i = 2; i <= upper; i++) { if (n % i == 0) flag = false; } Print(flag, n);}bool TraditionalMethod(int n) { int upper = floor(sqrt(n)); for (int i = 2; i <= upper; i++) { if (n % i == 0) return false; } return true;}int uniform(int a, int b) { return (rand() % (b - a)) + a;}LL Pow(int a, int n) { LL sum = 1; for (int i = 1; i <= n; i++) { sum *= a; } return sum;}void Fermat(int n) { bool flag = true; srand((unsigned)time(0)); int a = uniform(1, n); if (Pow(a, n - 1) % n != 1) flag = false; Print(flag, n);}bool Btest(int a, int n) { int s = 0, t = n - 1; do { s++; t /= 2; } while (t % 2 != 1); int x = 1; while (t--) { x = (x * (a % n)) % n; } if (x == 1 || x == n - 1) return true; for (int i = 1; i < s; i++) { x = (x * x) % n; if (x == n - 1) return true; } return false;}bool MillRab(int n) { int a = uniform(2, n - 1); return Btest(a, n);}bool RepeatMillRab(int n, int k) { for (int i = 1; i <= k; i++) { if (MillRab(n) == false) return false; } return true;}void PrintPrimes() { int pn = 2, count = 2; printf("2 3 "); int n = 5; do { if (RepeatMillRab(n, 10)) { // 当k=10时,误判概率低于百万分之一 if (TraditionalMethod(n)) pn++; count++; printf("%d", n); if (count % 20 == 0) printf("\n"); else printf(" "); } n += 2; } while (n < 10000); printf("误判个数:%d", count - pn); double correct = (double)(pn) / count * 100; printf("\n正确比例:%f%%\n", correct);}int main() { srand((unsigned)time(0)); PrintPrimes(); return 0;}

    ##运行结果运行结果如下:

    2 3 5 7 11 13 17 19 23 29 31 37 ...误判个数:3正确比例:99.30%

    (根据实际运行结果可能会有所不同,具体结果取决于随机数生成的结果)

    以上为完整代码及运行结果,展示了如何利用改进后的Miller-Rabin测试方法高效地判定整数是否为素数。通过多次重复测试并结合传统方法,误判概率得以显著降低。

    上一篇:C++实现二叉树的最近公共祖先
    下一篇:基于Windows2003实现网关-网关虚拟专用网络

    发表评论

    最新留言

    表示我来过!
    [***.240.166.169]2025年05月05日 23时23分25秒