【CINTA课程学习——判别素数】

前言

根据《信息安全数学基础》课程内容第五章 素数与素数测试的学习,列出了三种判断整数是否是素数的算法。
习题:判断111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111131111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111是否是素数。


一、试除法

简单的方法–试除法(trial division),
代码如下:

1 bool IsPrime(int n){
2 for(int i = 2; i * i <= n; i++){
3 if(n % i == 0) return false;
4 }
5 return n != 1
6 }
#include <iostream>
using namespace std;

bool IsPrime(long long n) {

    for (long long i = 2; i * i <= n; i ++) {
        if (n % i == 0 ) {
            return false;
        }
    }

    return true;
}

int main() {
    long long number_to_test = 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111131111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111;
    bool result = IsPrime(number_to_test);
    cout << "该整数是" << endl;
    cout << (result ? "素数" : "合数") << endl;
    return 0;
}

结果由于测试整数太大无法运行
改进:

#include <iostream>
#include <string>
using namespace std;

string addStrings(const string& num1, const string& num2) {
    string result;
    int carry = 0;
    int i = num1.size() - 1;
    int j = num2.size() - 1;

    while (i >= 0 || j >= 0 || carry) {
        int sum = carry;
        if (i >= 0) sum += num1[i] - '0';
        if (j >= 0) sum += num2[j] - '0';

        result.push_back('0' + (sum % 10));
        carry = sum / 10;

        if (i >= 0) i--;
        if (j >= 0) j--;
    }

    reverse(result.begin(), result.end());
    return result;
}

string multiplyStrings(const string& num1, const string& num2) {
    if (num1 == "0" || num2 == "0") return "0";

    string result(num1.size() + num2.size(), '0');

    for (int i = num1.size() - 1; i >= 0; i--) {
        int carry = 0;
        for (int j = num2.size() - 1; j >= 0; j--) {
            int product = (num1[i] - '0') * (num2[j] - '0') + (result[i + j + 1] - '0') + carry;
            carry = product / 10;
            result[i + j + 1] = '0' + (product % 10);
        }
        result[i] += carry;
    }

    if (result[0] == '0') result.erase(result.begin());
    return result;
}

bool isPrime(const string& num_str) {
    string sqrt_str = "1";
    int sqrt_len = (num_str.size() + 1) / 2;
    for (int i = 0; i < sqrt_len; i++) {
        sqrt_str.push_back('0');
    }

    while (multiplyStrings(sqrt_str, sqrt_str) <= num_str) {
        sqrt_str = addStrings(sqrt_str, "1");
    }

    long long num_sqrt = stoll(sqrt_str);
    for (long long i = 2; i <= num_sqrt; i++) {
        if (num_str[0] != '0' && stoll(num_str) % i == 0) {
            return false;
        }
    }
    return true;
}

int main() {
    string num_str = "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111131111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111";

    string squared = multiplyStrings(num_str, num_str);
    string cubed = multiplyStrings(squared, num_str);

    bool result = isPrime(num_str);
    cout << "The number is " << (result ? "prime" : "composite") << endl;

    return 0;
}

将大整数存储为字符串,然后使用boost库来进行运算,但是我没有安装boost库,只能手动实现基本的大整数加法、乘法。中间又去学习了大整数知识。程序能够运行,但是涉及到非常大的整数运算和素性检测,计算时间超级长,没等到结果。可以再试试分段计算和boost库。

二、米勒测试

高效的素性判定算法:费尔马小定理

费尔马小定理
如果 p 是素数,对任意 a ∈ Z 且 p ∤ a,以下等式成立:ap-1≡ 1 (mod p)

米勒测试基于费马小定理推广而来,利用上述性质,可以设计素数判定算法:多次随机选择a,检验上式是否成立。如果不成立,则p是合数;如果成立;p可能是素数。

需要注意的是:还存在伪素数,特别是 Carmichael 数的问题,它们也可能使等式成立。

米勒测试的思路:
设 n > 2 是一个奇素数,则 n − 1 可表达为:n − 1 = 2kq
其中,q 是一个奇数,k 是某个正整数。设 a 是任意选取的整数,且 gcd(a, n) = 1。
如果以下两个条件其中之一得到满足:

  1. aq ≡ 1 (mod n)
  2. 存在某个 0 ≤ j ≤ k − 1,使得 a2jq ≡ −1 (mod n)

则称 n 通过了以 a 为基的米勒测试。

米勒测试定理
设 n 是奇素数,对任意满足 gcd(a, n) = 1 的整数 a,n 必然会通过以 a 为基的米勒测试。

米勒测试存在误判可,但通过重复测试可以使误判概率极小。它避免了仅仅检验a(n-1)≡1(mod p)的方法可能发生的判错。可以看作是费马小定理方法的改进。

#Input:a是随机选取的基,n是要测试的整数,而q是整数满足n-1=2^k q
#Output:如果n是合数,输出0;否则n可能是素数,输出1,即通过米勒测试
def MillerTest(a, q, n):
    x = pow(a, q, n)
    if (x == 1) or (x == (n - 1))return 1
    while q != (n - 1);
       x = (x * x) % n
       q *= 2
       if x == (n - 1):
           return 1
    return 0

现在来判定一下111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111131111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111

结果:是素数

三、Miller-Rabin算法

Miller-Rabin算法是建立在米勒测试基础上的改进随机化素数判定算法。相较于米勒测试:

  1. 改进了判定流程,增加了随机性
    米勒测试是针对一个给定基a进行判定。Miller-Rabin算法中,每次选择一个随机整数a作为基,重复执行多轮判定。labin
  2. 引入错误概率分析
    拉宾测试给出了合数通过米勒测试的概率上界。Miller-Rabin算法利用此结果,通过重复判定控制总的错误概率。
  3. 减小了误判概率
    对同一合数,Miller-Rabin算法误判概率比米勒测试小得多,更可靠。

Miller-Rabin算法的基本思路:

  • 分解n-1的形式为2^r*q,其中d是一个奇数,r是非负整数。
  • 重复选择不同的a进行多轮测试
  • 如果任何一次失败,n是合数;如果所有轮都通过,n很可能是素数
  • 通过重复轮数控制错误概率
#Input:整数n和米勒测试的次数
#Output:如果n通过k次米勒测试,输出1,否则输出0
def IsPrime(n, k):
    q = n - 1
    while is_even(p):
        q /= 2
    for i in range(k):
        a = randint(2, n - 1)
        if not MillerTest(a, q, n):
            return 0
    return 1

总结

知识点:三种判定素数的方法
复盘:将这几种方法从理论运用到实践的过程中还是出现了很多问题,在解决问题的过程中也学了很多其他东西。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,这里是50种不同国家的语言表达“我爱你”: 1. English - I love you 2. Spanish - Te quiero 3. French - Je t'aime 4. German - Ich liebe Dich 5. Italian - Ti amo 6. Portuguese - Eu te amo 7. Russian - Ya lyublyu tebya 8. Chinese (Mandarin) - Wo ai ni 9. Japanese - Aishiteru 10. Korean - Sarang hae 11. Arabic - Ana behibak (to a male) / Ana behibek (to a female) 12. Dutch - Ik hou van je 13. Danish - Jeg elsker dig 14. Swedish - Jag älskar dig 15. Norwegian - Jeg elsker deg 16. Finnish - Minä rakastan sinua 17. Polish - Kocham Cię 18. Czech - Miluji Tě 19. Hungarian - Szeretlek 20. Bulgarian - Obicham te 21. Greek - S'ayapo 22. Turkish - Seni seviyorum 23. Romanian - Te iubesc 24. Croatian - Volim te 25. Serbian - Volim te 26. Slovenian - Ljubim te 27. Slovak - Milujem Ťa 28. Estonian - Ma armastan sind 29. Latvian - Es tevi mīlu 30. Lithuanian - Aš tave myliu 31. Icelandic - Ég elska þig 32. Albanian - Te dua 33. Thai - Phom rak khun (to a male) / Chan rak khun (to a female) 34. Vietnamese - Anh ye^u em (to a female) / Em ye^u anh (to a male) 35. Indonesian - Saya cinta padamu 36. Filipino - Mahal kita 37. Hindi - Main tumse pyar karta hoon 38. Bengali - Ami tomake bhalobashi 39. Urdu - Main tumse muhabbat karta hoon 40. Marathi - Me tujhe pyaar kartaa hoo 41. Punjabi - Main tere pyar da haan 42. Telugu - Nenu ninnu premisthunnanu 43. Tamil - Naan unnai kaadhalikken 44. Malayalam - Njan ninnodenikkoo 45. Kannada - Naanu ninna preetisuttene 46. Gujrati - Hu tane pyar karoo chu 47. Nepali - Ma timilai maya garchu 48. Sinhala - Mama oyata arderyi 49. Burmese - Chit pa de 50. Mongolian - Bi chamd hairtai
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值