热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

SICP:费马小定理与素数检测

我知道费马等一些人都热衷于“纯数学”,那些被看起来毫无实用价值的“纯理论”,可这费马检查,却是全世界的服务器每秒中都要运行无数次的RSA算法的理论基石。就我自己而言,每天使用SSH的时候都要用到。而几位科学家把这这一切联系起来的过程,实在称得上是“玄妙”了。

SICP 1.2.6

费马小定理

关于费马小定理,读到注解的时候,还是有点震撼的。

皮埃尔?得?费马(1601-1665)是现代数论的奠基人,他得出了许多有关数论的重要理论结果,但他通常只是通告这些结果,而没有提供证明。费马小定理是在1640年他所写的一封信里提到的,公开发表的第一个证明由欧拉在1736年给出(更早一些,同样的证明也出现在莱布尼茨的未发表的手稿中)费马的最著名结果——称为费马的最后定理——是l637年草草写在他所读的书籍《算术》里(3世纪希腊数学家丢番图所著),还带有一句注释“我已经发现了一个极其美妙的证明,但这本书的边栏太小,无法将它写在这里”。 找出费马最后定理的证明成为数论中最著名的挑战。完整的解最终由普林斯顿大学的安德鲁?怀尔斯在1995年给出。

我知道费马等一些人都热衷于“纯数学”,那些被看起来毫无实用价值的“纯理论”,可这费马检查,却是全世界的服务器每秒中都要运行无数次的 RSA 算法的理论基石。就我自己而言,每天使用 SSH 的时候都要用到。而几位科学家把这这一切联系起来的过程,实在称得上是“玄妙”了。

费马小定理:

如果 n 是一个素数,a 是小于 n 的任意正整数,那么 a 的 n 次方与 a 模 n 同余。(两个数称为是模 n 的同余,如果它们除以 n 的余数相同。数 a 除以 n 的余数称为 a 取模 n 的余数,或简称为 a 取模 n)。

如果 n 不是素数,那么,一般而言,大部分的 a

对于给定的整数 n,随机任取一个 a

读起来理解不直观?那么我这么总结下吧。

假如a是一个整数,p是一个素数,那么 ap = a (mod p)

如果a不是p的倍数,这个定理也可以写成 ap-1 = 1 (mod p)

举个例子,67是一个素数,则266 mod 67 = 1。

费马检测

费马检测基于费马小定理,费马小定理:

如果n是一个素数,a是小于n的任意正整数,那么a的n次方与a模n同余。

但是如果n不是素数,一般来说大部分的 a

实现费马检查的的方法:

;; 计算一个数的幂对另外一个数取模的结果
;; 
(define (expmod base exp m)
        ;; 如果 exp 等于 0,那么返回0
  (cond ((= exp 0) 1)
        ;; 如果 exp 是偶数
        ((even? exp)
         ;; square(expmod(base (exp/2) m)) % m
         (remainder (square (expmod base (/ exp 2) m))
                    m))
        ;; 如果不是偶数
        (else
         ;; (base * expmod(base(ex1 - 1) m)) % m
         (remainder (* base (expmod base (- exp 1) m))
                    m))))

;; 费马检测
(define (fermat-test n)
  ;; 定义方法调用expmod
  (define (try-it a)
    (= (expmod a n n) a))
  (try-it (+ 1 (random (- n 1)))))

;; 快速求素数
(define (fast-prime? n times)
  (cond ((= times 0) true)
        ((fermat-test n) (fast-prime? n (- times 1)))
        (else false)))

expmod 函数实现了求 base 的 exp次幂,然后再将结果余上m,得出来的结果再与a比较,如果相等,那么这个数可能为素数。

费马检测的C语言实现

由于 lisp 的语法太过奇葩,在这里贴一个 C/C++ 的实现吧:

#include "stdio.h"
#include "math.h"

#define TRUE 1
#define FALSE 0

typedef int Status;

int square(int n)
{
    return n*n;
}
/*---------------------------------------------------
计算一个数的幂对另一个数取模的结果,
确定是否素数所需的步数将具有θ(log n)的增长阶
---------------------------------------------------*/
int expmod(int base, int exp, int m)
{
    if (exp == 0)
    {
        return 1;
    }
    else if ((exp % 2) == 0)
    {
        return square(expmod(base, exp / 2, m)) % m;
    }
    else
    {
        return (base * (expmod(base, exp - 1, m))) % m;
    }
}

/*---------------------------------------------------
执行费马检查需要选取位于1和n-1之间(包含这两者)的数a,而后检查a的n次幂取模n的余数是否等于a.
---------------------------------------------------*/
Status fermat_test(int n)
{
    int a = rand() % n; /*a random int, less than n*/
    printf("本次随机值为%d\n", a);
    if( a == expmod(a, n, n) )
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}
/*
bool fermat_test(int n)
{
    // a is a random number in range (1~99)
    int a = rand() % (n - 1) + 1;
    return expmod(a, n, n) == a;
}
*/

Status fermat_prime(int n, int times)
{
    if (0 == times)
    {
        return TRUE;
    }
    else if( fermat_test(n) )
    {
        return fermat_prime(n, times-1);
    }
    else
    {
        return FALSE;
    }
}

Status is_prime(int n, int test_count)
{
    int i;
    // The result can be extremely reliable
    // when TEST_COUNT is big enough.
    for (i = 0; i 

费马检测是一个相对可靠的算法,而且在实现大数判断素数时可以提供相对高的效率来工作。下面看看费马检测概率问题。

概率方法

从特征上看,费马检查与我们前面已熟悉的算法都不一样。前面那些算法都保证计算的结果一定正确,而费马检查得到的结果则只有概率上的正确性。说得更准确些,如果数 n 不能通过费马检查,我们可以确信它一定不是素数。而 n 通过了这一检查的事实只能作为它是素数的一个很强的证据,但却不是对 n 为素数的保证。我们能说的是,对于任何数 n,如果执行这一检查的次数足够多,而且看到 n 通过了检查,那么就能使这一素数检查出错的概率减小到所需要的任意程度。

不幸的是,这一断言并不完全正确。因为确实存在着一些能骗过费马检查的整数:某些数 n 不是素数但却具有这样的性质,对任意整数 a

能够证明,存在着使这样的出错机会达到任意小的检查算法,激发了人们对这类算法的极大兴趣,已经形成了人所共知称为概率算法的领域。在这一领域中已经有了大量研究工作,概率算法也已被成功应用于许多重要领域。

PS 1:能够骗过费马检查的数称为 Carmichael 数,我们对它们知之甚少,只知其非常罕见,在 100 000 000 之内有 255 个 Carmichael 数,其中最小的几个是 561、1105、1729、2465、2821 和 6601。在检查很大的数是否为素数时,所用选择是随机的。撞上能欺骗费马检查的值的机会比宇宙射线导致计算机在执行“正确”算法中出错的机会还要小。对算法只考虑第一因素而不考虑第二因素恰好表现出数学与工程的不同。

PS 2:概率素数检查的最惊人应用之一是在密码学的领域中。虽然完成 200 位数的因数分解现在在计算机上还是不现实的,但用费马检查却可以在几秒内判断这么大的数的素性。这一事实成为 Rivset、Shamir 和 Adleman (1977) 提出的一种构造“不可摧毁的密码”的技术基础,这一 RSA 算法已经成为提高电子通信安全性的一种使用广泛的技术。因为这项研究和其他相关研究的发展,素数研究这一曾被认为是“纯粹”数学的缩影,是仅仅因为其自身原因而被研究的课题,现在已经变成在密码学、电子资金流通和信息查询领域里有重要实际应用的问题了。

后话

本来想一篇文章搞定素数检测与费马小定理,但是发现这个素数检测是个大坑,里面还有很多东西挖据。既然开坑了,后面开个专题慢慢填坑吧。。。不断开坑,不断填坑,学到的东西会很多。

本文地址:http://www.nowamagic.net/librarys/veda/detail/2329,欢迎访问原出处。


推荐阅读
  • Linux服务器密码过期策略、登录次数限制、私钥登录等配置方法
    本文介绍了在Linux服务器上进行密码过期策略、登录次数限制、私钥登录等配置的方法。通过修改配置文件中的参数,可以设置密码的有效期、最小间隔时间、最小长度,并在密码过期前进行提示。同时还介绍了如何进行公钥登录和修改默认账户用户名的操作。详细步骤和注意事项可参考本文内容。 ... [详细]
  • LVS实现负载均衡的原理LVS负载均衡负载均衡集群是LoadBalance集群。是一种将网络上的访问流量分布于各个节点,以降低服务器压力,更好的向客户端 ... [详细]
  • 学习SLAM的女生,很酷
    本文介绍了学习SLAM的女生的故事,她们选择SLAM作为研究方向,面临各种学习挑战,但坚持不懈,最终获得成功。文章鼓励未来想走科研道路的女生勇敢追求自己的梦想,同时提到了一位正在英国攻读硕士学位的女生与SLAM结缘的经历。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 本文介绍了使用PHP实现断点续传乱序合并文件的方法和源码。由于网络原因,文件需要分割成多个部分发送,因此无法按顺序接收。文章中提供了merge2.php的源码,通过使用shuffle函数打乱文件读取顺序,实现了乱序合并文件的功能。同时,还介绍了filesize、glob、unlink、fopen等相关函数的使用。阅读本文可以了解如何使用PHP实现断点续传乱序合并文件的具体步骤。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 如何在服务器主机上实现文件共享的方法和工具
    本文介绍了在服务器主机上实现文件共享的方法和工具,包括Linux主机和Windows主机的文件传输方式,Web运维和FTP/SFTP客户端运维两种方式,以及使用WinSCP工具将文件上传至Linux云服务器的操作方法。此外,还介绍了在迁移过程中需要安装迁移Agent并输入目的端服务器所在华为云的AK/SK,以及主机迁移服务会收集的源端服务器信息。 ... [详细]
  • 31.项目部署
    目录1一些概念1.1项目部署1.2WSGI1.3uWSGI1.4Nginx2安装环境与迁移项目2.1项目内容2.2项目配置2.2.1DEBUG2.2.2STAT ... [详细]
  • C语言判断正整数能否被整除的程序
    本文介绍了使用C语言编写的判断正整数能否被整除的程序,包括输入一个三位正整数,判断是否能被3整除且至少包含数字3的方法。同时还介绍了使用qsort函数进行快速排序的算法。 ... [详细]
  • C语言常量与变量的深入理解及其影响
    本文深入讲解了C语言中常量与变量的概念及其深入实质,强调了对常量和变量的理解对于学习指针等后续内容的重要性。详细介绍了常量的分类和特点,以及变量的定义和分类。同时指出了常量和变量在程序中的作用及其对内存空间的影响,类似于const关键字的只读属性。此外,还提及了常量和变量在实际应用中可能出现的问题,如段错误和野指针。 ... [详细]
  • SpringBoot整合SpringSecurity+JWT实现单点登录
    SpringBoot整合SpringSecurity+JWT实现单点登录,Go语言社区,Golang程序员人脉社 ... [详细]
  • 恶意软件分析的最佳编程语言及其应用
    本文介绍了学习恶意软件分析和逆向工程领域时最适合的编程语言,并重点讨论了Python的优点。Python是一种解释型、多用途的语言,具有可读性高、可快速开发、易于学习的特点。作者分享了在本地恶意软件分析中使用Python的经验,包括快速复制恶意软件组件以更好地理解其工作。此外,作者还提到了Python的跨平台优势,使得在不同操作系统上运行代码变得更加方便。 ... [详细]
  • ejava,刘聪dejava
    本文目录一览:1、什么是Java?2、java ... [详细]
author-avatar
NOYOKI要跑偏
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有