最近做题目看到一个关于原根的概念,尽管不知道有什么用但是概念还是好理解的。
想要获得一个数n的原根,就要去计算1到n-1的1到n-1次方,如果这个数的1到n-1次方关于n的mod都不相同,那么这个数就是n的原根。
我的理解能力比较差所以单是这个概念就看了好久,如果上下文中表述有错误的话欢迎各位指正与探讨。所以接下来我们要获取一个数的原根。
如果这个数字比较小的话自己手算加个计算器其实也可以,比方说算个7的原根之类的也就36个数,然后最大的也就是6的6次方,但悲伤的是作业叫我们算37,36个数最大还是36的36次方,按计算器都按爆掉,于是只能用电脑了。
按照要求写出了下述代码,只是为了作业就没有优化了,运行一些大一点的数字估计会慢很多,比方说我输了个两百万电脑基本就不会有反应,尽管两百万也没有原根就是了……
#include <stdio.h>
int main(){
int num;
int count=0;
printf("give the number you want to get primitive roots:");
scanf("%d",&num);
for (int i=1; i<num; i++) {
for(int j=1; j<num; j++){
int shu = i;
for(int n=1; n<j; n++){
shu = shu*i%num;
}
if(shu==1){
count++;
}
}
if(count==1){
printf("%d ",i);
}
count=0;
}
}
对于电脑计算来讲比较麻烦还是数据较大,比方说一开始我想的是先求出数值再求模,但是参数装不下,于是乎我们就用到(a(mod n)*b(mod n))(mod n)=a*b(mod n),在每一步求模这样数据就会小很多,用int就能装下。但是代码里面的方法效率也比较低,因为当前每一个数字都需要从头开始计算,打比方我们在算n的某一行,从a^1到a^(n-1)由于每一步都需要从头开始计算,相当于我们光这一行就经历了(n-1)*n次计算,而创建数字进行继承的话就只需要n次。
扯了有点多,接下来的问题是我们如何进行判定,一开始想不通啊,不知道怎么判定啊,直接把所有数字遍历出来导进excel里面一行一行对过去……
一整个密密麻麻看得眼睛都花了,所以怎么看呢,经过表格上面的比对,我们可以发现最后一列的余数全部都是1!也就是说如果再乘一次不管哪个数都会重复回一次时的余数,妙啊,然后我们再看那些有重复,也不会是突然变出一个和之前一样的数字,而是以1结尾开始循环,妙,实在是太妙了,为什么是这样的呢?
我也蛮好奇的,有没有大佬可以告诉我证明思路……但是不管怎么说有规律可循就是好事,所以判断这个数是不是原根的条件就是这一行里面是不是只有一个1,只有一个1就输出,不止一个的就不是原根,这样就不用一个个去判定了,善哉~
根据这一条思路其实我们还可以简化判定流程,因为出现重复必然以1结尾,而重复也必然是完整的循环,所以我们只要判定特定位置上的数字是不是1就可以了,那么这个特定位置就是这个数字的因数,以36为例,它的全部因数有1,2,3,4,6,9,12,18,36。首尾可以忽略,而2,3,4,6,9,又是12和18的因数,可以说只要12 和18位是1,那么这一行就必然有循环,所以我们可以知道这个特定位置就是这个数字n和它质因数的商。计算次数又一次减少了,善哉~
这么一说就觉得之前自己那一行行看过去就是白看了,心又有点累起来了……
总而言之能够初步理解就好了,这个是网络安全课上的内容,发布主要是当做学习笔记帮助自己加深记忆,后续可能会发布一些古典密码还有其他相关内容,有大佬看到的话多指点我一下。同时感谢大家看到最后,共同进步,一起努力吧。