网络安全课 06 【Euler、Fermat定理、Miller-Rabin 概率算法】

计算最大公因数、最小公倍数

 

Euler 函数

 

 

Fermat定理

 

星期四的计算需要由中间过程,推算出3^3000%6 = 3   而 3^3%7 = 6 

大数的素数分解

Miller-Rabin大数 素性检测实现 

视频讲解链接(需要梯子)

https://www.youtube.com/watch?v=eC6YCv6sMzE

C++实现代码:

#include <iostream>
#include <string>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <time.h>
#include <Windows.h>

using namespace std;

#ifndef ll
#define ll long long
#endif
// rand 2 - e
ll rand_Number(ll e) {
    return rand() % e + 1;
}
// a*b % c  快速乘 + mod
ll mult_mod(ll a, ll b, ll c) {
    a %= c;
    b %= c;
    ll res = 0;
    while (b) {
        if (b & 1) {
            res += a;
            res %= c;
        }
        a <<= 1; //左移一位 相当于 a*=a
        if (a >= c) a %= c;
        b >>= 1;  //b 下一位
    }
    return res;
}

//a^u % num  快速幂  里面套快速乘
ll getRemainder(ll a, ll u, ll num) {
    ll cur = 1;
    ll nxt = a;
    while (u) {
        if (u & 1) {
            cur = mult_mod(cur, nxt, num);  //cur *=nxt  %num
        }
        nxt = mult_mod(nxt, nxt, num);  //nxt *=nxt
        u = u >> 1;
    }
    return cur % num;
}


bool checkPrime(ll num) {
    int S = 20; //检测次数

    if (num == 2) {
        return true;
    }
    if (num < 2 || num % 2 == 0) {
        return false;
    }
    ll u = num - 1; //肯定是偶数

    while (u % 2 == 0) {
        u /= 2;
    }
    //这个时候 num = 2^(u*k) + 1

    for (int i = 0; i < S; i++) {
        ll a = rand_Number(num - 1);  //随机取一个小于num的数做检测  作为底数a^u % num
        ll x = getRemainder(a, u, num);  //a^u % num
        ll x_1;
        ll tu = u;
        while (tu < num) {
            x_1 = mult_mod(x, x, num); //x=a^u   x*x=a^2u  x*x % num
            if (x_1 == 1 && x != 1 && x != num - 1) {
                //如果x_1==1  要满足 上一个x 是 1 or num-1  才没有非平凡根
                //如果出现根不是 1 or num-1  那么就存在非平凡根  那num就是和数
                return false;
            }
            if (x_1 == 1 && (x == 1 || x == num - 1)) {
                //已经出现1   后面再平方没意义
                return true;
            }
            x = x_1;
            tu *= 2;  //继续平方  算 a^2u  a^4u  a^8u
        }
        if (x != 1) {
            return false;
        }
    }
    return true;
}

int main() {
    ll n;
    scanf("%lld", &n);

    DWORD t1, t2;
    t1 = GetTickCount();
    if (checkPrime(n)) {
        cout << "Yes" << endl;
    } else {
        cout << "No" << endl;
    }
    t2 = GetTickCount();
    printf("Use Time:%f
", (t2 - t1) * 1.0 / 1000);
    return 0;
}

  

  

  

原文地址:https://www.cnblogs.com/Stephen-Jixing/p/12736077.html