哒哒哒!掌握一种心理学的学习概念,人的认知是不断成长的,不必要因为一时的失意,而否定您。

数学不好,也没关系,一起成长。早在出生起,我们每天笨拙的咿呀咿呀学汉语与走路,我们最终都学会了。为什么,因为那时候的我们,不会在意别人的眼光,不会怕做的不好就不去练习。

来吧,短暂人生路,让我们一起拥有手眼通天的胆量!更重要的是,如果您可以认真看完这里的,数论可以算入门了,不过我会实时更新,常回来看看哈,RSA加密数论部分更新ing。


                                                                                          《目录》

  • 数论基础前置知识:
  • NO. 1 约数篇[因数]
  • 什么是素数
  • 素数验证方法:
  • 威尔逊定理趣谈
  • GCD 最大公约数 与 LCM 最小公倍数
  • 威尔逊定理证明的一种方法:
  • 模 %
  • 费马大定理

数论基础前置知识:

整除:

  • 如果 a 被 p 整除,a 是 p 的倍数,记为:p | a ,如  3 | 9 ,  1 | 9,  9 | 9; 其中 1、9 是9的频繁因子 , 3是9的非频繁因子。

传递性:

  • 如果 a 是 p 的倍数,那么 a 的倍数也是 p 的倍数,如 2 | 4 , 4 | 12 . 故有 2 | 12,记为  a | b, b | c, 则 a | c。

整数的质因数分解 :

  • 一个正整数拆分为质数的幂的乘积,如 24 =  2 * 2 * 2 * 3 =  *  , 17 = 

  • 质因数分解采用短除法【小学知识】

唯一分解定理 :【数论基石,也叫算术基本定理】

  • 正整数的质因数分解是唯一的 , n =  *  *  ··· , 是质数,如上 24 和 17。

质因数分解看除法 :

如 ,12 =  *   ,  180 =  *  *  , 那么;

易发现,正整数的除法,即把俩个数的质因数分解,接着每个质数的质数相减。

质因数分解看整除 :

m | n , 显然 是当且仅当 n ➗ m 是整数。[ 4 | 12    =>    12  ➗ 4 ]

解释一下,如果 ,那么算出来的就是一个分数,不是整数。如,

学了这些,我们就可用这个代替整除,把 n 和 m 质因数分解,然后对比指数。

如果 n 每一个质数的指数都大于等于m 的对应指数,那么 n 就是 m 的倍数 !!

编程,只学理论,不敲代码;都是耍流氓

题目:20 * 30 * 50 / 60 * 70 / 80 * 90 和 7 是否 相等。

             3 min ...

那么,暴力高精度 O() , n 是数字长度,可是太慢。用 double 计算,如果有上万次运算,精度无法保证。

需要指出,我们可以采用 刚刚学习的质因数分解方法解,您看最大数 90,90以内的素数只有 24 个。[利用容斥原理也可以得到素数个数 , , , 小于9的素数只有4个, 2、3、5、7,解出来]

我们把每个整数分解成质数的幂,然后存储这些指数。

乘法 : 指数相加   [如果是加法,那只能高精度了]

除法 : 指数相减   [如果是减法,那只能高精度了]

判断是否相等 :  判断每一个指数是否相等 [唯一分解定理]


  • #include <iostream>
    using namespace std;
    const int n = 24;
    int prime[n] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89};struct Hi
    {int flag, r[n];   // r[] 存储每个质数的指数friend Hi operator * (Hi a, Hi b)   //  指数加法{Hi ans;for( size_t  i = 0; i < n;  i ++ )ans.r[i] = a.r[i] + b.r[i];return ans;}friend bool operator != (Hi a, Hi b)  // 判断指数是否相等{for( size_t  i = 0; i < n;  i ++ )if( a.r[i] != b.r[i] )  return true;return false;}
    };int main(void)
    {// 同九义汝何秀return 0;
    }

NO. 1 约数篇[因数]

  1. 整数 a(4) 能被整数 b(2) 整除,a(4) 叫做 b(2) 的倍数,b(2) 就叫做 a(4) 的约数。
  2. 约数个数是有限的,记为 d(n) (自然数是这样 - 从0开始的整数)
  3. 所有数的约数都包含 自身 和 (或) 1

借 图.jpg 献计:

请看,n = 1 , d(n) = 1   =>   1 的约数有且只有一个即 1;

n = 10 , d(n) = 4  => 10 的约数共 4 个即 1、2、5、10;

其余数同。

那么想一想,我们怎么把这个表格打出来??  莫急莫急,要成长,就需要建立新的神经元连接,数学与思考正是良计!!


​​#include <stdio.h>
#define N 1000
int d[N];  // 默认为 0 ,存储在 .data 段// 计算 [1,n] 的约数个数 O(n log n)
void fews(int n){for( int i = 1; i <= n; i ++ ){for( int j = i; j <= n; j += i ) // 枚举 i 的所有倍数,换一个角度想,本来是约数d[j] ++;}
}// 【人之千虑,比有一得 ~ ,您的方法是怎么样的,推敲一遍】
int main(void)
{int cnt = 0;int n;scanf("%d",&n);fews(n);for( int i = 1; i <= N; i ++ )if(d[i])  cnt++,printf("%-3d%c",d[i],cnt%10 ? ' ' : '\n');printf("\n[1,n] 每个数约数表");return 0;
}

下面选修 ~

数论的基石,唯一分解定理解析约数个数。

一个数  ··· ,且 [a , b , c] > 0,   如 

这里指数一一对应, a 可取 {0,1,2} , b 可取 {0,1,2} , c 可取 {0,1} , (a,b,c) 一共3 * 3 * 2 = 18种取法,每种取法对应一个约数。

e.g.   a , b , c 都取 1 时, ,而 30 就是 180 的一个约数。

所以,如果一个数 n 可以分解   为      , 则 ta 的约数有  

e.g.  180      ,  ,  d(n) = (2+1) * (2+1) * (1+1)  = 18 种。

OK,欢迎在评论区或者邮件分享您的代码哦·简单的理解了约数和倍数,接下来学习的素数,是数论里的?,非常重要。

许许多多的理论与问题都围绕素数建立,如

  • 被用于电影,安全码,谜题,甚至是大学教授的孤独主题
  • 哥德巴赫猜想
  • 是否有无穷多个梅森素数
  • 第六代加密算法 - RSA非对称加密法 [手机支付加密、网银加密]
  • 斐波那契数列是否存在无穷多个素数
  • 费马大定理是否成立
  • 黎曼猜想
  • 孪生素数是否有无穷多组 [间隔为2,如 (3,5) , ... ,(71,73) , ...]
  • 中国剩余定理 [韩信点兵、物不知数]
  • 自然界多数生物的生命周期(年)是素数,最大限度减少碰见天敌的机会[蝉昆虫每隔13或17年从地面发芽]
  • 机械中齿轮的齿数是素数,以增加俩⚙️俩个相同齿相遇啮合次数的最小公倍数 [提高了耐用度, 减少故障]
  • ... ...

可见素数不是一般的重要,上面列举出来的,程序员是要学习与理解的,只为优质的算法效率足以。

P.S. 我会将上面的问题,都解出来,不过,大概需要一些时间。star ~


什么是素数

数学定义: 素数, 又叫质数, 是指在一个大于 1 的自然数中, 除了1 和 自身外, 无法被其他自然数整除的数。

p.s. 1 、0, 即非素数又非合数,素数也是 "不可分割数" 。

  • Primes是所有数字的基石。就像在化学中一样,了解材料的化学结构有助于理解和预测其性质。
  •  Primes具有特殊属性,如难以确定(是的,即使是困难也可能是一个积极的特征)。这些属性可用于加密,循环以及查看其他数字如何相乘。

小学生都明白的概念,可是,从古至今,多少数学家都想能明白素数的排列的规则,却找不到其具体的分布的规律,只知道是螺旋排列,如下图

每一个黑点都是一个素数 ~

介绍一个程序里算法常模质数 : 19260817。在计数问题中,由于产生的数据规模非常大[高精度问题],这时候要规定一个范围,通常情况是模一个素数。大部分情况 选 19260817 就好,大小合适,也是质数。

目前我知道最大的素数是 2017年12月全球合作项目 "互联网梅森素数搜索" 中由 现年51岁的田纳西州的电气工程师Jonthan Pace 在自己电脑上,发现了M77232917,即 2的77232917次方 - 1。啧啧,不愧是电气工程师,电脑配置肯定杠杠的 ~

素数验证方法:

方法一: 枚举 2 ~ n-1, 如果 n % i == 0, 则 n 为合数
             代码略 ... ...  O(n²);


方法二: 优化方法一, 若一个数是合数, 则必有一个小于等于ta的平方根的因数 O(n√n)
             比如, n = 15, n 的素数有 1、3、5, 除数5因为再 n 被3整除时, 其商是5, 也就表示 n 能被 5 整除。


#include <stdio.h>
#include <math.h>bool is_prime(size_t n)
{size_t qn = sqrt(n);for( int i = 2 ; i <= qn; i ++ )if( qn % i == 0 )return false;return true;
}int main(void)
{printf("%d\n",is_prime(1));return 0;
}

加油加油 ~


方法三: 埃拉托色尼筛  O( n log logn )

一个合数可以被一个不超过 ta 的平方根的素数整除,如果,为找出不超过 100 的素数的个数,首先注意不超过 100 的合数一定有一个不超过 10 的素因子。由于小于 10 的素数只有 2 、3、5、 7,因此不超过 100 的素数就是这 4 个素数以及那些大于 1 和不超过 100 且不被 2、3、5、7 整除的正整数。

把 n 个自然数按次数排序,可用计数数组。
               step-0: 筛去 0、1 , 先算出 根号n 的长度,就不用每次循环 i*i 或者 sqrt(n) [优化步骤, 可省略]
               step-1: 筛去 合数, 减少一半时间
               step-2: 筛去 2的倍数
               step-3: 筛去上一步没筛的第一个数(3)的倍数
               step-4: 筛去上一步没筛的第一个数(5)的倍数 [如果没去合数,那么就是4, 下面同理,所以说减一半时间]
               step-5: 筛去上一步没筛的第一个数(7)的倍数
               step-6: 第一个划掉的数字总是当前这轮所用素数的平方, 避免重复判断[优化步骤,可省略]
               step-7: 一直循环, 最后留下来的就是不超过n的素数

请看动图

如,i 为 24 时,i 模了 2, 3 (没优化合数和模4) 。

#include <stdio.h>
#include <math.h>
#define Max 1000
int flag[Max];  // 默认为0, 存储在 .datavoid Init(int *a);
void Eratosthenes( size_t n );  // O( n log(logn) )int main(void)
{size_t cnt = 0;size_t n = Max;Init(flag);Eratosthenes(n);printf("\t\t[2,%d] 素数表:>\n\n",Max);for ( int i = 2; i < Max; i++ )if( !(flag[i]) )cnt++, printf("%-5d%c", i, cnt % 8 ? ' ': 10);printf("\n\n%d %s %u", Max, "以内的素数共", cnt);return 0;
}void Eratosthenes( size_t N )
{for (int i = 2; i * i <= N; i++)    // 试除 [2,√n]{if ( !(flag[i]) )          // 筛选素数的标志{for (int j = i * i; j <= N; j += i)   // 筛去 i * n,即 i 倍
// 每一轮筛选时, 第一个划掉的数字总是当前这轮所用素数的平方{flag[j]++;}}}
}void Init(int *a) // 去合数,优化步骤 step-0
{for( int i = 4; i * i <= Max; i += 2 )  // 合数形式 2n if( i & 0x1 == 0 )   // 同 % 2a[i] ++;
}

欧拉筛法(线性筛)  :过程同埃筛,不过只模最小质数。 加油,下面有举例。不过,我先讲清楚原理,您认真看上面的动图,可以发现,会有重复筛除的合数。比如 30,在 i = 2 时,会筛30,i = 5 时,会筛30,所以就有了线性筛。

#include <stdio.h>
#include <math.h>
#define Max 1000int flag[ Max ], cnt;       // 默认为0, 存储在 .data
void Init(int *a);
int juge[ Max ];
void Euler( size_t N );          // O( n )int main(void)
{size_t cnt = 0;size_t n = Max;Init(flag);Euler(n);printf("\t\t[2,%d] 素数表:>\n\n",Max);for ( int i = 2; i < Max; i++ )if( !(flag[i]) )cnt++, printf("%-5d%c", i, i % 8 ? 32 : 10);printf("\n\n%d %s %u", Max, "以内的素数共", cnt);return 0;
}// 改动部分
void Euler( size_t N )
{for( int i = 2;  i <= N;  i ++ )  // 枚举每个数{if( !flag[i] ) juge[cnt++] = i;  // juge[] 存储素数for( int j = 0; i * juge[j] <= N;  j ++ )   // 枚举已经筛好的素数{flag[i * juge[j]] ++;   // 筛去合数, 任何合数都可以写为多个素数积if( !( i % juge[j] ) )  break;  // 保证 p[j] 是 i * p[j] 最小的素因子, 每个数只被最小质因数筛}}
}void Init(int *a)   // 去合数
{for( int i = 4; i * i <= Max; i += 2 )if( i & 0x1 == 0 )   // 于 % 2a[i] ++;
}

对于上面的程序只改动了这一个接口,这一接口相对上面的埃筛,不同的是最后取模 if(..) break 因为ta 保证取最小素数模。

如,i 为 24 时,i 只模了 2; 还有 3, 4, 并没有模。

方法五,比 欧拉筛 更快。 思路,空间换时间

俩种实现,第一种,把目前所有知道的素数按顺序存储在一个数组里 [大数存储要设计算法]

第二种,把一定范围的素数按照数组下标缓存,是素数,那么对应下标设为0 [个人爱好]。

说到空间,这里有一种节约空间的方法。位图筛法求素数,代码拿出来好好研究(在理解埃筛后补习一下位操作)。

#include <stdio.h>
#include <stdlib.h>
#define SHIFT  5           // 2的5次方, 一个int占32位
#define MASK  0x1F         // 0x0001 1111const int N = 100;
int state[ (N>> SHIFT) + 1 ];     // 申请 100 位 (N>>SHIFT):100-(32*3) = 4 bits
int totalPrime[N];                      // 记录有多少个素数bool isPrime( int x )
{  return !( state[x>>SHIFT] & (1<<(x & MASK) ) );  }    // 获取结果,0为素数 接着取反 !0 = 1, 所以打印时素数变成 1  void Prime( void )
{memset(totalPrime, 0, sizeof(totalPrime) );     // 记录素数的数组清零memset( state, 0, sizeof(state) );              // 状态数组清零state[0] |= (1<<0);                             // 设置 0 为合数类(规定 1 不是素数)state[0] |= (1<<1);                             // 设置 1 为合数类(规定 1 不是素数)for( size_t i = 2; i < N; i ++ ){totalPrime[i] = totalPrime[i-1];            // 因为记录是一个数组,所以需要加上之前统计的if( (state[i>>SHIFT] & (1<<(i&MASK) ) ) )   // 获得状态,是 真 即合数continue;for( size_t j = i*i; j < N; j += i )state[j>>SHIFT] |= (1<<( j&MASK) );     //  位设置if( isPrime(i) )                            //  如果是素数计数++totalPrime[i] ++;}
}int main(void)
{Prime( );size_t cnt = 0;for( size_t i=0; i<N; i ++ )cnt ++,printf("%4d : %-4d%c", i, isPrime(i), cnt&3?'\t':'\n' );  // cnt&3 == cnt%4printf("\n  共 %d 个素数",totalPrime[cnt-1]);return 0;
}

2019,新年快乐,祝一切顺利。

当然,如果对素数有兴趣。可以参加全球合作项目 "互联网梅森素数搜索"GIMPS。1996年迄今为止,ta 共找到了16个梅森素数。

Jonthan Pace 获得了 3000 美金,虽然不多但很有意义。发现更多的素数,可以帮助数学家更深入的理解,素数是在上面情况下出现。

【赏金】 GIMPS:

  • 谁第一个找到 1 亿位的素数会有 15 万美元的奖励
  • 谁第一个找到 10 亿位的素数会有 25 万美元的奖励

目前,找素数都是分布式网络,许多的计算机联合暴力计算完成。因为,谁也没有发现素数具体的分布规律,也没有特定的公式,所以找素数的任务交给了 GIMPS。

下面正式进入素数的世界【反证法,证明素数是无穷多个

预先给定几个素数,则有比他们更多的素数。

设 a, b, c 为给定的素数, 构造一个数 A 等于 给定素数相乘变为合数再加一

       形如, A = a * b * c + 1

       那么 A   可以质因数分解嘛 ?[表示成上述的质数他们的乘积]

      很显然,我们用其中任何一个素数均不能整除 A 。

  • 要么 A 本身是一个素数,那么 A 就不等于 a , b , c 任意一个数。
  • 要么 A 能被不同于 a , b , c 的某个数整除。

无论,上述哪种情况。必然存在一个素数 s 不同于已有的素数a, b, c ;

  • 2 * 3 * 5 + 1 = 31
  • 3 * 5 * 7 + 1 = 106 = 2 * 53

也就是说,有了 n 个素数,就可以构造出第 n + 1 个素数,因此素数有无穷多个。

素数是有限的,这不是谬论吗?

      所以,质数数是无穷的!!质数存储在螺旋数字里的分布也只是模糊的螺旋状。相信,当我们知道的素数达到一定界限时,我们可以找到一条定理来描述素数分布的规律,ta实在太重要了,对数学家,编程爱好者都是如此。

-------------------------------------------------------------------------------------------------------------------------------

威尔逊定理趣谈

有人说,如果一个人不知道威尔逊定理,那么ta的 算术 算是白学了!

夸张吗 ~ 我觉得是有戏剧性的。那您可知道,ta为什么这么说呢??事实上,威尔逊定理是莱布尼茨首先发现的,后经拉格朗日证明的;威尔逊(这里是人名,英国法官J.  Wilson)的一位擅长拍马屁的朋友 沃润(E.  Waring) 于 1770年出版一本书里说,这条定理是威尔逊发明, 而且对外说这条定理永远不会被证明(因为缺少好的符号来处理素数),这话被高斯听见了,当时高斯也不清楚拉格朗日证明了这条定理。站在 blackboard 前 5 分钟,就证明了这条定理。所以,高斯说,威尔逊差的不是符号,而是概念。

故事说完了,定理我们展开慢慢说。

-------------------------------------------------------------------------------------------------------------------------------

威尔逊定理 :

  • 若 p 为素数, 则    (其中 !表示  阶乘),

则威尔逊定理也成立,即:

  • 若对某一正整数 p,有 (p-1)! + 1 一定是 p 的倍数,所以再利用 sin 函数的特点,可以构造出一个素数分布的函数曲线     这个函数值为 0 的点都是素数所在的点。

稍稍解释一下,如果看了不明白,那么看一下同余。

威尔逊定理应用很广,例如对较大的质数 p,我们虽然无力算出 (p-1)! 的值,但却知道 (p-1)! 被 p 除但余数是 -1 或 p - 1。事实上,由于 (p-1)! + 1 可被 p 整除,则存在自然数 n,使得 (p-1)!  + 1 = np,(p-1)! = np - 1 = (n-1)p+(p-1),所以 (p-1)! 被 p除的余数是 -1 或者 p - 1。

我假定,数论您是零基础的,没关系,我们一起解读。

先学习一个同余的概念,选修 ~

  ,ta 意味着 32 - 2 = 5 * n, n =》6

若 a, b 为俩个整数,且它们的差 a - b 能被某个自然数 m 所整除,则称 a 就模 m 来说同余于b,或者说 a 和 b 关于模 m 同余,记为 ,等同 a - b = m * k (k是整数)  。

推出: (p-1)! + 1  =   p * n,OK 同余补习好了,请看上面的红色推导部分吧。

如果我们要判断 p 是否是素数,那么就看 p 满不满足   ,满足就是质数。

#include <iostream>
using namespace std;const int Q = 20;void factorial(long long (&fac)[Q] )  // 传引用, 求阶乘
{for( size_t i=1; i<=Q; i ++ ){fac[i] = fac[i-1] * i;}
}
// 可以换 预处理阶乘 或 快速乘bool check( long long *fac, size_t p )   // p 为一个正整数
{if( fac[p-1]%p == p-1 )    // fac 阶乘数组 [公式: (p-1)! + 1 = p * n]return true;     return false;
}
// 威尔逊逆定理 , O(n) 容易爆 long longint main(void)
{long long fac[Q] = {1,1};factorial(fac);for( size_t i=2; i<=Q; i ++ ){if( check(fac,i) )cout<<i<<" ";}return 0;
}

其实,这定理。有点费呀,n! 阶乘,对于计算机的内存都是 很伤的,按照 一位算法工程师角度说,这应该是一个无效的坏算法!

下面,是证明威尔逊定理的一种方法。[学会证明,是数学学习的一种很好的偷懒方法因为高效]

设 p 是素数,p = 2 时,定理成立不足道。考虑到所占空间较多,我在博客最后证明。

-------------------------------------------------------------------------------------------------------------------------------

GCD 最大公约数 与 LCM 最小公倍数

有俩个数 n and m,ta们的最大公约数 gcd(n,m) ,满足 d | n 与 d | m 的最大值 d。

那么 d 是多少 ? 如果从质因数分解的角度说,d的指数要尽可能大,但得小于等于 n 和 m 的最小指数[如果选 n 和 m最大指数,就是 最小公约数]。

e.g.   

GCD(n,m) =》 n 和 m 质因数分解,于是每个质数取其在 n , m 中最小指数。

LCM(n,m) =》 n 和 m 质因数分解,于是每个质数取其在 n , m 中最大指数。

下面讲解,gcd 证明,选修 ~

xxx

编程,只学理论,不敲代码;都是耍流氓

俩个数的 GCD 我们用 欧几里得算法,LCM 这里有一个很漂亮很漂亮的性质。

GCD(n,m) * LCM(n,m) = n * m

下面证明,为什么是这样的,选修 ~   [前置技能 :  质因数分解]

    ···

   ···

p.s. 实际不止 2 , 3 , 5 ,还有更多素数,不过,这个公式衔接我还不会,所以,··· 加不上。

质因数分解那里,有说俩数相乘就是指数相加。

 ,  are you ok , 是不是有点感觉 ?

故,

就等于 n * m        ,         证毕 。

 ,   程序写法 : lcm = n * m / gcd(n,m);

 程序里面,您可不能这样写,因为 n * m 较大时, 可会爆 long long 。想一想,要改成什么样呢 ???

答 :  ,  程序写法 : lcm = n / gcd(n,m) * m;

求GCD我知道的实现方法:

  • 暴力枚举、
  • 更相减损、
  • 辗转相除(也叫欧几里得)
  • 二进制算法(更相减损+辗转相除优化)、
  • 贝祖等式优化欧几里得(辗转相除)、
  • 硬件+奇偶优化

代码更新ing...

威尔逊定理证明的一种方法:

对于奇素数,令 , 则  中不会对于除数 p 同余的俩个数; 事实上,若  ,,则  可被 p 除尽,而 ,但 B 中数不可能被 p 除尽。    于是 B 中数被 p 除得到的余数形成的集合 C = {1, 2, ··· , p-1}。

设 B 中被 p 除余 1 的数 是 :

  1. 若 ,则  被 p 除于 a ,又 a  2,与  矛盾,故
  2. 若 ,则 ,ta 被 p 除余 a,所以 
  3. 若 ,则 ,由于  ,故应有  ,  这只能是 a = 1 或 a = p-1,此与  矛盾,故 

由 1、2、3 得,,且 

a 不同时, 亦相异; 若 ,  且 ,因 ,  而 B 中数关于 mod p 不同余,可见  ,  则  。

依次取 a 为 2, 3, ···, ; 使  的数  分别为    即:>

从而

2 * 3 * ··· (p-2)    1 (mod p)

又    (p-1)!    -1 (mod p),则

(p-1)! = 1 * 2 * 3 * ··· * (p-2) * (p-1)    -1 (mod p)

从而 (p-1)! + 1 可被 p 除尽。

若 p 是合数, p 有因数 q,  从而 (p-1)! 可被 q 整除;(p-1)! + 1 不能被 q 整除,亦不能被 p 整除。


计算机RSA算法部分数论知识

Miller_Rabin素数判定 :有一定概率会失败,我们称这样判断的素数为 "工业素数",我在加密博客RSA算法判断素数时便采用的  Miller_Rabin素数判定。

数论学家利用费马小定理研究出许多种素数测试方法,Miller_Rabin素数测试算法是其中一种,其过程如下:

  1. 计算奇数 M,使得 
  2. 选择一个随机数 A < N
  3. 对于任意 i < r,若 ,则 N 通过随机数 A 的测试
  4. 或者,若 ,则 N 通过随机数 A 的测试
  5. 让 A 取不同的值对 N 进行 5 次测试,若全部通过则判定 N 为素数

若 N 通过一次测试,则 N 不是素数的概率为 25% ,若 N 通过 t 次测试,则 N 不是素数的概率为 。事实上,t = 5 时,N 不是素数的概率为 ,N 为素数的概率已经大于 99.99%。实际应用中,可首先用 300 ~ 500 个小素数对 N 进行测试,以提高Miller_Rabin素数测试通过的概率,从而提高测试速度。而在生成随机素数时,选取的随机数最好让 r = 0,则可省去 步骤3 的测试,进一步提高测试速度。

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
const int cnt = 10;int modular_exp( int a, int m, int n )    // 模幂运算采用平方 -- 乘降幂法算法(下面的模运算细说),RSA 加密重点, 可以改成迭代
{if( 0 == m )    return 1;if( 1 == m )    return ( a % n );long long w = modular_exp( a, m>>1, n );w = w * w % n;if( m & 1 )     w = w * a % n;return w;
}
/* 平方 -- 乘降幂法算法: 避免出现 大数的中间值,比如俩个 200 位素数相乘变成 40000 位的中间值 */bool Miller_Rabin( int n )
{if( 2 == n )    return true;for( int i = 0; i < cnt; i ++ ){int a = rand( ) % ( n - 2 ) + 2;if( modular_exp( a, n, n ) != a )    return false;}return true;
}int main(void)
{srand( time(NULL) );int n;scanf("%d",&n);if( Miller_Rabin(n) ) printf("%s","Probably a prime\n");  // 质数elseprintf("%s","A composite\n");  // 合数return 0;
}

假如随机数选取 4 个数是 2、3、5、7,则在  以内唯一一个判断失误的数为 3 215 031 751。


费马定理 :  若 p 为素数,a 为正整数,且 a 和 p 互质,则 :

证明 :

首先,p-1 个整数 a, 2a, 3a, ··· (p-1)a 中没有一个是 p 的倍数。

其次,a, 2a, 3a, ···(p-1)a 中没有任何俩个同余于模 p 的。

于是 :  a, 2a, 3a, ···(p-1)a 对模 p 的同余既不是0,也没有俩个同余相同,因此,这 p-1 个数对模 p 的同余一定是 1, 2, 3, ···p-1 的某一种排列,即:

化简为 :

又由于 p 是素数,根据威尔逊定理得出 (p-1)! 和 p 互质。所以约去 (p-1)!,得到 :

其实这是一种特殊形式,一般情况下,若 p 为素数,则 : ,这就是著名的费马小定理。


欧拉定理 :  若 a 与 m 互质,则 

费马定理是用来阐述在素数模下,指数的同余性质。当模是合数的时候,就要应用范围更广的欧拉定理了。

欧拉函数 : 对正整数 n,欧拉函数是小于等于 n 的数中与 n 互质的数的数目。

欧拉函数又称为  函数,如 ,因为 1、3、5、7 均和 8 互质。

引理( 1 ):

1.  如果 n 为某一个素数 p,则 ;

2.  如果 n 为某一个素数 p 的幂次 ,则 : ;

3.  如果 n 为任意俩个互质的数 a、b 的积,则 :  ;

证明:

1.  显然;

2.  因为比   小的正整数有  个。其中,所有能被 p 整除的那些数可以表示成   ,即共有  个这样的数能被 p 整除,从而不与   互质。所以,;

3.  在比 a * b 小的 a * b - 1 个整数中,只有那些既与 a 互质(有  个),又与 b 互质(有  个)的数,才会与 a * b 互质。显然满足这种条件的数有  个。所以 

比如: 要求 ,因为40 = 5 * 8,且  5 和 8 互质,所以: 。而 

引理( 2 ):

设  为正整数 n 的素数幂乘积表达式,则:

证明:  由于诸素数幂互相之间是互质的,根据引理(1)得出:

比如:  

素数的一般判别方法:

  1. 枚举   优化为  
  2. 威尔逊逆定理      基本没用,需要大数计算来扩展
  3. Miller_Rabin素数判定  ,RSA加密术用 C/C++ 实现需要实现大数,让俩个素数达到 1024 位以上
  4. Eratosthenes埃筛      非常接近线性
  5. 欧拉筛(线性筛)  
  6. 位图筛法 时间复杂度同筛法,空间复杂度极小~
  7. 安利资料:判定素数

模 %

模 广泛应用,

  • 时钟、手表是 模 12 系统;
  • 计算机的 n 位运算器是 模 n 系统,
  • 算盘 也是一个模系统;
  • 哈希算法本质也是模 运算,让余数保持在一个固定的范围。
  • 我们约定的星期几,其实也是一个模 7(6) 系统,
  • Web 编程的分页也是 模运算
  • ... ...

加法模,例如时钟,10 - 4 = 10 - (12 - 4) = 10 + 8 = 6 (mod 12),

模  7 系统里, 3 + 3 = 6 (mod 7), 6 + 6 = 5(mod 7),

乘法模,在模 13 系统里, 11 * 9 = 8 (mod 13),

11 * 9 = 99 % 13 = 8,

模的另外一种表现形式 : n % p  是否整除可以写为  ,还可以扩展代替除法

随时取模(加法和乘法):

  • (a+b)%p = (a%p + b%p) % p ,运用这个模性质,不会让 程序里的 a + b 溢出;
  • (a*b)%p = [ (a%p) * (b%p) ] %p,基本同上;

利用上面俩个性质,可将模幂运算转化成模乘运算如,以计算 % n 为例,可以分解为( % n × a % n)%n,将 % n又可以继续分解为( % n ×  % n)%n, % n最终分解为( % n ×  % n)%n , % n 即 (a % n * a % n)%n。


费马大定理

当 n  3 时, 方程不存在自然数解。


数论推荐资料:基础数论模版大全\勾股数组

数论[计算机数学专题(5)]相关推荐

  1. 数论与数学专题练习(一)(201802~201805)

    数论与数学专题练习(一)(201802~201805) 手动博客搬家: 本文发表于20180224 00:33:28, 原地址https://blog.csdn.net/suncongbo/artic ...

  2. 集合论[ 计算机数学专题(1) ]

    中学老师说,集合论是现代数学的基础,很多定义都是基于集合论的.如,数列.函数都以集合研究的. 其实我觉得老师,讲的,毫无影响,所以,我就带您重新感受集合的魅力. 我整理了几个关于集合的问题给您. 集合 ...

  3. 机器学习数学方面的介绍[计算机数学专题(9)]

    在学习机器学习之前,应该具有坚实的计算机基础. 深入学习了数据结构与数据结构的算法.计算机组织和系统架构,也具有编写一个完整项目的能力. 我的 AI 专题,主要是以 高中数学 为基础的,所以您应该看看 ...

  4. 计算几何[计算机数学专题(4)]

                                                                                         <目录> 介绍 解 ...

  5. 计算机的数学思想源头(回复“计算机数学”可下载PDF典藏版)

    计算机的数学思想源头(回复"计算机数学"可下载PDF典藏版) 2018-04-16 数据简化DataSimp 数据简化DataSimp导读:前篇<计算机诞生的详细历史> ...

  6. 计算机数学专业是应用数学专业吗,大学数学系的数学与应用数学专业学什么课程内容?...

    数学,现在大多分为纯数学和应用数学,但最终都是应用数学. 数学与应用数学是计算机专业的基础和上升的平台,是与计算机科学与技术联系最为紧密的专业之一,在计算机领域做出很好的成果的,大多是数学专业背景.在 ...

  7. 训练指南——数学专题一的总结

    差不多一个星期过去了,在这一个多星期里,我做了一个数学专题和两场训练赛,要说对自己的感觉,只能说很差劲,开始的时候以为环境会比现在宽松很多,后来才发现想法是错误的,实验室室里室一种紧张的气氛,感觉就像 ...

  8. sql相同顺序法和一次封锁法_数学专题 | Ep01 隔板法的妙用

    数学专题(一)  隔板法的妙用 浓度常见哪些问题? 排列组合分堆?涂色?到底掌握透彻了吗? 解析几何与韦达定理? 公式总是记不住?应用题还不会解? 除了写作(写作听我的).逻辑(逻辑说)专题外,本周起 ...

  9. 计算机辅助设计技术案例,【智能科技学院】学院前沿技术运用课程组开展“计算机辅助设计”专题讲座...

    3月19日下午,智能科技学院前沿技术运用课程组在学术报告厅开展了"计算机辅助设计"专题讲座,讲座对计算机辅助设计技术在专业中的运用做了具体讲解.主讲人由智能科技学院教师黄毅担任. ...

最新文章

  1. R语言问题剖析20篇(一)-R语言泛函式编程purrr实现优雅循环迭代
  2. python生成10000个样本数据集_python产生随机样本数据
  3. CoolQ/DingTalk 实现CI/CD消息推送到群
  4. 线性搜索或顺序搜索算法在Java中如何工作? 示例教程
  5. 兰州交通大学计算机科学与技术学院,兰州交通大学计算机科学与技术
  6. 每个人都是生活的导演
  7. java远程关机_通过jsch实现对linux服务器的shell客户端远程控制关机完整示例代码分享...
  8. c语言二进制加法_“整形数”还真没那么简单(C语言版)
  9. 英语词汇辨异 —— 形近字、近义词
  10. java.lang.NoSuchMethodError: org.springframework.web.context.ConfigurableWebApplicationContext.setId
  11. hdu 1426(DFS+坑爹的输入输出)
  12. Golang - Structs 包的使用
  13. BLE 技术(四)--- 链路层五种通信模式和空口协议设计 (Core_v5.2)
  14. 迷你商城后端管理系统 ———— stage2 项目的核心代码实现
  15. 压缩软件替代方案BandZip
  16. 北京 | 微信小程序及小游戏开发者线下交流会
  17. 2017-2018 ACM-ICPC, Asia Daejeon Regional Contest (大部分题解)
  18. Java 生成验证码。随机产生一个四位数的验证码,每位数可能是数字、大写字母或小写字母。
  19. 5、kubernetes Scale Up/Down在线增加或减少 Pod 的副本数、Failover故障转移、用 label(标签)控制 Pod 的位置
  20. android imageview 拉伸图片大小,【教程】安卓保证图片长宽比的同时拉伸图片

热门文章

  1. 难处理的js单引号与双引号问题解决
  2. 高德地图Demo,生成apk发布到手机签名不一致
  3. 弹性云服务器有什么用
  4. 视觉定位系统在机器人全场定位的应用
  5. 关于华为实习的一两点感触
  6. 巴比特 | 元宇宙每日必读:连续七个季度出现亏损,Meta元宇宙部门Q2亏损28 亿美元,扎克伯格称这种情况可能会持续数年...
  7. %I64d 和%lld 的区别
  8. java计算 月数_Java 计算开始年月到结束年月期间的年月数
  9. 紧跟时代步伐,朗强HDMI分布式矩阵可以通过手机来控制
  10. Spark Mllib里的分布式矩阵(行矩阵、带有行索引的行矩阵、坐标矩阵和块矩阵概念、构成)(图文详解)...