【密码学】RSA的大整数雏形

 2019.11.23:


这个代码一开始采用的是如《算法笔记》上等PAT中的类似题目将十进制数字转换为数组大整数(也是十进制形式)。

但是这种想法在后来实现加密的时候快速积出现了严重的弊端,和普通十进制并没有什么区别了,依旧拖慢进程大的可怕。

今天课设答辩同学们都做出了像毕设一样的作品,很完善的调用各种类实现各种混合加密,还有图形化界面,python、java、各种语言起飞。到了我这,可怜的连个运行起来都有问题。

下面的代码是256进制的刚起步,老师说不要这样转换,可以直接用long int类型读入(C++),然后直接转换为256进制。

我在下面的写法没有抛弃原来的10进制大整数。

#include <iostream>
#include <string>
#include<algorithm>
#include <fstream>
#include <sstream>
#include <iostream>
using namespace std;

/*1.生成密钥对,(e,d,n),公钥是(e,n),私钥是(d,n)
步骤如下:
求n(准备两个质数p,q。这两个数不能太小,太小则会容易破解,将p乘以q就是N),
求f=(p-1)(q-1)
求e :gcd(e,f)=1
求d:e*d mod f = 1
2.加密:用(e,n):密文 c=m^e(mod n)
3.解密:用(d,n):明文 m=c^d(mod n)
*/
//定义大整数结构体,使用保存十位数字每一位的方法
struct bigint{
	int d[1000];
	int len;
	bigint(){
		memset(d,0,sizeof(d));
		len=0;
	}
};
bigint e,d,p,q,n;


struct bigint256{
	int d[32];
	int len;
	bigint256(){
		memset(d,0,sizeof(d));
		len=0;
	}
};


int compare(bigint a,bigint b){//比较a和b的大小,a大、相等、a小分别返回1,0,-1
	if(a.len>b.len)return 1;//a大
	else if(a.len<b.len)return -1;//a小
	else{
		for(int i=a.len-1;i>=0;i--){
			if(a.d[i]>b.d[i]) return 1;//只要有一位a大,则a大
			else if(a.d[i]<b.d[i])return -1;//只要有一位a小,则a小
		}
		return 0;
	}
}
void print(bigint a){
	for(int i=a.len-1;i>=0;i--){
		cout<<a.d[i];
	}
}
//出错的原因:求解exgcd没有成功,是因为没有定义负数的运算!==
//重载大整数的运算
 //进制转换需要转换为256进制

bigint change(char str[]){
	bigint a;
	a.len=strlen(str);
	for(int i=0;i<a.len;i++){
		a.d[i]=str[a.len-i-1]-'0';
	}
	return a;
}

    char s0[3]="0";
	char s1[3]="1";	
	char s2[3]="2";
	char s3[3]="3";
	bigint in0=change(s0);
	bigint in1=change(s1);
	bigint in2=change(s2);
	bigint in3=change(s3);



//重载大整数减法
bigint operator - (bigint a, bigint b)
{
	bigint temp;
	int sign=1;
	if(compare(a,b)<0){
		temp=a;
		a=b;
		b=temp;
		sign=-1;
	}
	//cout<<"a:";print(a);cout<<endl;
	//cout<<"b:";print(b);cout<<endl;

	bigint c;
	int carry = 0;//carry是进位
	for(int i=0;i<a.len||i<b.len;i++){//以较长的为界限
		if(a.d[i]<b.d[i]){
			a.d[i+1]--;//向高位借位
			a.d[i]+=10;
		}
		c.d[c.len++]=a.d[i]-b.d[i];//减法结果为当前借位结果
	}
	while(c.len-1>=1&&c.d[c.len-1]==0){
		c.len--;//去除高位的0,同时至少保留1位最低位
	}
	if(sign==1)return c;
	else if(sign==-1){
		c.d[c.len-1]=-c.d[c.len-1];
		return c;
	}
}
//重载高精度加法
bigint operator + ( bigint a, bigint b)
{
	if(a.d[a.len-1]<0&&b.d[b.len-1]>0){
		a.d[a.len-1]=-a.d[a.len-1];
		return b-a;
	}
	if(a.d[a.len-1]>0&&b.d[b.len-1]<0){
		b.d[b.len-1]=-b.d[b.len-1];
		return a-b;
	}
	int sign=1;
	if(a.d[a.len-1]<0&&b.d[b.len-1]<0){
		b.d[b.len-1]=-b.d[b.len-1];
		a.d[a.len-1]=-a.d[a.len-1];
		sign=-1;
	}
	
	bigint c;
	int carry = 0;//carry是进位
	for(int i=0;i<a.len||i<b.len;i++){
		int temp=a.d[i]+b.d[i]+carry;//两个对应位与进位相加
		c.d[c.len++]=temp%10;
		carry=temp/10;//十位数为新的进位
	}
	if(carry!=0){
		c.d[c.len++]=carry;
	}
	while(c.len-1>=1&&c.d[c.len-1]==0){//清高位零
		c.len--;}
	if(sign==1)return c;
	else if(sign==-1){
		c.d[c.len-1]=-c.d[c.len-1];
		return c;
	}
}
//重载大整数除法
/*
思想:反复做减法,看从被除数里面最多能减去多少个除数,商就是多少。
*/
//重新写一个减法,适合于返回长度,将数组直接做减法,参数是bigint中数组
int SubStract( int *p1, int *p2, int len1, int len2 )
{
    int i;
    if( len1 < len2 )
        return -1;
    if( len1 == len2 )
    {                        //判断p1 > p2
        for( i=len1-1; i>=0; i-- )
        {
            if( p1[i] > p2[i] )   //若大,则满足条件,可做减法
                break;
            else if( p1[i] < p2[i] ) //否则返回-1
                return -1;
        }
    }
    for( i=0; i<=len1-1; i++ )  //从低位开始做减法
    {
        p1[i] -= p2[i];
        if( p1[i] < 0 )          //若p1<0,则需要借位
        {
            p1[i] += 10;         //借1当10
            p1[i+1]--;           //高位减1
        }
    }
    for( i=len1-1; i>=0; i-- )       //查找结果的最高位
        if( p1[i] )                  //最高位第一个不为0
            return (i+1);       //得到位数并返回
    return 0;                  //两数相等的时候返回0
}

bigint operator / (bigint a, bigint b){//用一个例子方便写代码7546/23=328
	bigint c,z;
	if(a.len<b.len){
		return in0;
	}
	int len=a.len-b.len;//记录大整数a和大整数b的位数的差,方便下面给被除数b在低位补0,对齐a。len=2
	for(int i=a.len-1;i>=0;i--){
		//首先将原来位置的b的数字移到后边(高位)
		if(i>=len){
			b.d[i]=b.d[i-len];//与a的长度对齐,现在即是xx32 (数组是从低位到高位进行存储)
		}
		//如果差值到了,开始补零
		else{
			b.d[i]=0;
		}
	}
	b.len=a.len;//现在b的长度和a的长度一样了,b[]="0032"即大数2300
	//现在可以利用上面的不断做减法记录次数计算除法的结果了。可以知道商的位数最大是len+1,即差值+1。
	//所以外层循环是0-len,内层循环对商的每一位进行计数
	bigint a1=a;//为了防止改变a,新增一个变量a1,变为a的副本
	for(int j=0;j<=len;j++)
	{
		//需要更新外层循环中b的长度,如第一次7546-2300*3=646,第二次646-230*2=186```,每次减少1
		//注意b.len-1即因为运算是从低位开始“0032”即从下标0开始,
		//所以在新的while循环中指针b.d要从下一位开始,即“032”,长度相应的当然要减少一个
		while((c.len=SubStract(a1.d,b.d+j,a1.len,b.len-j))>=0){//对齐后如果减1次结果还是大于等于0,说明没有减净
			a1.len=c.len;//更新a1的长度,即被除数的长度为结果的长度,
			//如7532-2300-2300-2300=632,这个时候a1.d="236",因为SubStract函数将结果保存在了a1.d中,所以被除数自动更新,但是位数要自己手动
			z.d[len-j]++;//开始保存商的结果,接着进行减法	
			//cout<<"运算过程:z.d[len-j]"<<"z.d["<<len<<"-"<<j<<"]="<<z.d[len-j]<<endl;
		}
		z.len++;
	}
	 //错误:for( z.len;z.d[z.len]==0 && z.len>=0;z.len--);//求出的商可能跳过高位有0,所以再重新更新商的长度,如可能求出0030,把后面多余的0去掉	
	 //cout<<"z.len"<<z.len<<endl;
	while(z.len-1>=1&&z.d[z.len-1]==0){
	 z.len--;
	 }
	  //cout<<"z.len"<<z.len<<endl;
	 return z;
}
//重载大整数乘法
/*
列竖式找规律
如
   1   2   5
   X   5   3
先不要着急进位
1)125*3即 5*3 *1 + 2*3 *10 + 1*3 *100      = 15 *1 + 6  *10 + 3 *100
2)125*5即5*5 *10 + 2*5 *100 + 1*5 *1000   =         25 *10 + 10 *100 + 5 *1000

最后结果是 :a[0]->15*1进位1留5,a[1]->6+25+1=32 进位3留2,a[2]->3+10+3=16 进位1 留6,a[3]->5+1=6无进位   =>6625

找到规律ans[i+j]=a[i]+a[j];

*/
bigint operator * (bigint a, bigint b){//用一个例子方便写代码7546/23=328
	bigint z;
	z.len=a.len+b.len;
	for(int i=0;i<a.len;i++)//将因数各个位上的数字与另一个各个位上的数字相乘 
		{
			for(int j=0;j<b.len;j++)
				z.d[i+j]=z.d[i+j]+a.d[i]*b.d[j];//先乘起来,后面统一进行进位 
		}
		for(int i=0;i<z.len;i++)//进行进位 
		{
			if(z.d[i]>=10)  //若>=10 
			{
				z.d[i+1]=z.d[i+1]+z.d[i]/10;  //将十位上数字进位 
				z.d[i]=z.d[i]%10;  //将个位上的数字留下
			}
		}
		while(z.len-1>=1&&z.d[z.len-1]==0){//和上面一样清零
		z.len--;
		//cout<<"a1.len--;a1.len="<<a1.len<<endl;
	 }
		return z;
}

//重载大整数取模运算


//5%96?
bigint operator % (bigint a, bigint b){//用一个例子方便写代码7546/23=328
	bigint divTmp = a / b ;
	return (a - b * divTmp);
}



//===256==========256==================256===================
/*

转换的思想:
让bigint不断的除以256,采用除基取余的方法。
int z[40],num=0;//数组z存放Q进制y的每一位数,num为位数。
do{
z[num++]=y%Q;//模基取余法
y=y/Q;
}while(y!=0)//当商不为0时,进行循环。

*/
void printb(bigint256 bg)
{
	cout<<"打印256进制大整数"<<endl;
	for(int i=bg.len-1;i>=0;i--)
	{
		cout<<bg.d[i]<<",";
	}
}
char str256[4]="256";
bigint in256=change(str256);
bigint256 change256(bigint y){
	bigint256 z;
	z.len=0;
	 cout<<" print(y):"; print(y);cout<<endl;//测试
	bigint temp;
	do{
		temp=y%in256;
		 cout<<" print(temp):"; print(temp);cout<<endl;//测试
		//?如何将求模运算的结果保存在一个数组中,因为可能是0-3位数字。要存储在z.d[]的一个数值中
	//整型数组恢复正常十进制即可,a[0]*1+a[1]*10+a[2]*100	
	   for(int i=temp.len-1;i>=0;i--)
	   {
		   //只能先正序存,后面再逆过来
		   z.d[z.len]+=temp.d[i]*pow(10.0,(double)d.len-i);
		 // cout<<" printb(z):"; printb(z);cout<<endl;//测试
	   }
	   z.len++;
	   y=y/in256;
}while(compare(y,in0)!=0);
	int tt;
	for(int i=0;i<z.len-1;i++)
	{
		tt=z.d[i];
		z.d[i]=z.d[z.len-i-1];
		z.d[z.len-i-1]=tt;
	}
	cout<<" printb(z):"; printb(z);cout<<endl;//测试
	return z;

}







//重载完了大整数的基本运算后,来实现生成两个大整数P,Q(质数)
//自定义随机数发生器
bigint randb(int len){//输入十进制想要生成的质数的位数,注意1024bit是128字节即128位
	bigint a;
	a.len=len;
	for(int i=0;i<len;i++){
		a.d[i]=rand()/10;//使用rand()函数产生0-9以内的随机整数
}
	return a;
}
//为了方便,重载==
bool operator ==(bigint a,bigint b){
	if(compare(a,b)==0)return 1;
	else if(compare(a,b)==-1) return -1;
	else if(compare(a,b)==1) return -1;
}

//准备开始miller-Rabin算法
bigint Quick_Multiply(bigint a,bigint b,bigint mod)  //快速积(和快速幂差不多) 
{

	bigint ans=in0,res=a;
    while(compare(b,in0)!=0)//由于我没有重载比较运算符,但是在前面定义了compare函数,所以在这如果b<0则停止,应该是一样的。
    {
		
        if(b%in2==in1)
          ans=(ans+res)%mod;
        res=(res+res)%mod;
       // b>>=1;//右移相当于除以2
		b=b/in2;
    }
	while(ans.len-1>=1&&ans.d[ans.len-1]==0){//清高位零
		ans.len--;}
    return ans;
}
bigint Quick_Power(bigint a,bigint b,bigint c)     //快速幂
{
	
    bigint ans=in1,res=a;
	//if(b==in0)return in1;
    while(compare(b,in0)>0)//由于我没有重载比较运算符,但是在前面定义了compare函数,所以在这b=0则停止,应该是一样的。
    {
        //if(b&1)//b&1即b%2==1
		if(b%in2==in1){
        ans=ans*a%c;
		}
		a=a*a%c;
        // b>>=1;//右移相当于除以2
		b=b/in2;
    }
	while(ans.len-1>=1&&ans.d[ans.len-1]==0){//清高位零
		ans.len--;}
    return ans;
}

bool Miller_Rabin(bigint x)     //判断素数 
{
	
	//我们可以多选择几个 a,如果全部通过,那么 x 大概率是质数。
	char s5[3]="5";
	char s7[3]="7";	
	char s19[3]="19";
	char s23[3]="23";
	bigint in5=change(s5);
	bigint in7=change(s7);
	bigint in19=change(s19);
	bigint in23=change(s23);
	char s11[3]="11";
	char s13[3]="13";	
	char s17[3]="17";
	char s29[3]="29";
	bigint in11=change(s11);
	bigint in13=change(s13);
	bigint in17=change(s17);
	bigint in29=change(s29);
	bigint prime[10]={in2,in3,in5,in7,in11,in13,in17,in19,in23,in29};

    bigint k;
    bigint s=in0,t=x-in1,j;
    if(x==in2)  return true;   //2是素数 
   // if(x<2||!(x&1))  return false;     //如果x是偶数或者是0,1,那它不是素数 
	if(compare(x,in2)<0||(x%in2==in1)) return false;
   // while(!(t&1))  //将x分解成(2^s)*t的样子 
	while(t%in2==in1)
    {
        s=s+in1;
       // t>>=1;
		t=t/in2;
    }
   // for(i=0;i<10&&prime[i]<x;++i)       //随便选一个素数进行测试 
	 for(int i=0;i<10&&(compare(prime[i],x)<0);++i)
    {
        bigint a=prime[i];
        bigint b=Quick_Power(a,t,x);      //先算出a^t
        //for(j=1;j<=s;++j)    //然后进行s次平方 
		for(j=in1;compare(j,s)<=0;j=j+in1)
        {
            k=Quick_Multiply(b,b,x);   //求b的平方 
           // if(k==in1&&b!=1&&b!=x-1)     //用二次探测判断 
			if(k==in1&&compare(b,in1)!=0&&compare(b,x-in1))
              return false;
            b=k;
        }
        //if(b!=1)  return false;   //用费马小定律判断 
		if(compare(b,in1)!=0)  return false; 
    }
    return true;   //如果进行多次测试都是对的,那么x就很有可能是素数 
}

//1.随机生成两个质数p,q
bigint genPrime(int len)
{
	bigint res = randb(len);
//	Print(res);
	long loop = 20;
	long count = 0;
	while(!Miller_Rabin(res))
	{
		res = randb(len);
//		Print(res);
		count ++;
	}
//	cout<<count<<endl;
	while(res.len-1>=1&&res.d[res.len-1]==0){//清高位零
		res.len--;}
	return res;

}


/*
RSA中的e不能太小同样是密码学家D. Coppersmith,其于1990年指出[3]:
用于RSA的指数e不能太小,否则存在快速算法计算得到私钥d。这个定理要用到格密码学的著名算法LLL。
再次就不多做展开了… 不过需要注意的是,由于加密算法要计算m^e,如果e太大的话加密过程可能会比较慢。
现在一般认为令e=65537是比较合适的。
https://www.zhihu.com/question/54779059?sort=created
*/

bigint ex_gcd(bigint a,bigint b,bigint &x,bigint &y)      //扩展欧几里得
{
	//cout<<"compare(b,in0):"<<compare(b,in0);cout<<endl;
	

    if(compare(b,in0)==0)
    {
        x=in1;
        y=in0;
		//cout<<"b==in0"<<endl;
        return a;
    }
	/*cout<<"b!=in0"<<endl;
	cout<<"a:"<<endl;print(a);cout<<endl;
	cout<<"b:"<<endl;print(b);cout<<endl;
	cout<<"x:"<<endl;print(x);cout<<endl;
	cout<<"y:"<<endl;print(y);cout<<endl;cout<<endl;
	*/

	//bigint chu=a%b;
    bigint r=ex_gcd(b,a%b,x,y);
    bigint t=x;
    x=y;
    y=t-(a/b*y);//大整数的减法我没有定义如果结果为负数怎么办。
    return r;
}

bigint mod_reverse(bigint a,bigint n)//ax=1(mod n) 求a的逆元x
{
    bigint d,x,y;
    d=ex_gcd(a,n,x,y);
    if(d==in1){
		//cout<<"d==in1"<<endl;
		x=x+n;
		//cout<<"x=x+n;"<<endl;print(x);cout<<endl;
        return (x%n+n)%n;
	}
    else
        return in0;
}

bigint Get_e(bigint p,bigint q,bigint &x,bigint &y)
{	
	char stre1331[5]="1331";
	bigint in1331=change(stre1331);
	char stre65537[6]="65537";//备用
	bigint in65537=change(stre65537);

    //用欧几里德扩展算法求e,d。 随机选择一个整数 e,条件是1< e < f,且 e 与 f互质。
    bigint f =(p-in1)*(q-in1);

	//cout<<"\nf"<<endl;print(f);
	cout<<endl;

    //for(bigint j = in3; j < f; j+=1331)
	for(bigint j = in65537;compare(j,f)<0; j=j+in1331)//这里应该是挨个找,正好符合gcd(e,f)=1的时候,得到e。???这里出现问题!e怎么生成不了
    {
        bigint gcd=ex_gcd(j,f,x,y);
        //if( (gcd==1)&& x> 0)
		if( (compare(gcd,in1)==0)&& compare(x,in0)>0)
        {
            e = j;
            break;
        }
    }
    return e;//d为x.直接使用扩展欧几里得求出x后就可以用(x%m+m)%m得到(0,m)范围内的解。
}
 char tmp[10000];
int readMyf(){
	FILE *fp;
	fp = fopen("D://日常//大学文件//大三上学期//学科//安全协议//实验//MyCry02//mingwen.txt" , "r");
 
	fseek( fp , 0 , SEEK_END );
	int file_size;
	file_size = ftell( fp );
	cout<<"读取到文件大小为: "<< file_size<<endl;
    //ifstream file("filename");//D://日常//大学文件//大三上学期//学科//安全协议//实验//MyCry02//mingwen.txt
   
	fseek( fp , 0 , SEEK_SET);
	fread( tmp , file_size , sizeof(char) , fp);
	tmp[file_size] = '\0';
 
	fclose(fp);
    cout<<"文件内容为     : "<< tmp <<endl;
	return file_size;
}
bigint code;
bigint message;
void RSA_Encrypt(){
	//对明文加密c=m^e(modn) 用前面的大整数幂运算Quick_Power(m,e)即可
	//首先从本地读取明文
	int file_size;
	file_size=readMyf();//读取到文件
	//获取数组tmp[file_size] 
	bigint bigming=change(tmp);//转换为bigint类型。
	cout<<"转换为bigint类型"<<endl;print(bigming);cout<<endl;
	//注意:这里有很大的缺陷,对于空格和英文字母及大小写,需要重新写函数进行转换和映射才可以,时间有限这里待完善

	
	code=Quick_Power(bigming,e,n);
	cout<<"加密后的文件内容为:"<<endl;
	print(code);cout<<endl;
   //cout<<str<<endl;
}
void RSA_Decrypt(){
	//解密:m=c^d(mod n)
	
	message=Quick_Power(code,d,n);
	cout<<"解密后的文件内容为:"<<endl;
	print(message);cout<<endl;
}
void initskey()//生成p,q,e,d,初始化密钥
{

	p= genPrime(56);//选择生成1024bit的p和q,2^N有N*log2位数,2^1024=1.675*10^308;(是309位数)
	q= genPrime(56);
	cout<<"生成大素数p,q"<<endl;
	cout<<"p:";print(p);
	cout<<"\nq:";print(q);
	bigint f1=p-in1;
	bigint f2=q-in1;
	bigint f=f1*f2;//Stack around the variable 'f' was corrupted出现错误:怎么修改:project->配置属性->c/c++->代码生成->基本运行时检查 设置为默认值

	char stre65537[6]="65537";//备用
	bigint in65537=change(stre65537);

	cout<<"\n随机生成私钥e"<<endl;
	bigint x,y;
	e=Get_e(p,q,x,y);
	cout<<"--------》e:";print(e);  
	cout<<"\n生成公钥d"<<endl;
	d=mod_reverse(e,f);
	cout<<"d:";print(d);
     n=p*q;
}

//hash函数,将需要传送的信息hash成大整数,然后进行运算加密。?这里卡壳了,hash好像不可逆,是用于签名的。那这里直接对消息进行加密?全部转换成ASCII码?





int main()
{
	
	/*char str1[1000],str2[1000];
	cin>>str1>>str2;
	bigint num1=change(str1);
	bigint num2=change(str2);
		//测试加法
	bigint sum=num1+num2;
	cout<<"\n****测试大整数加法结果********"<<endl;
	print(sum);
	cout<<"************"<<endl;
	  //测试减法
	bigint sub=num1-num2;
	cout<<"\n****测试大整数减法结果********"<<endl;
	print(sub);
	  //测试大整数除法
	bigint mul=num1/num2;
	cout<<"\n****测试大整数除法结果********"<<endl;
	print(mul);
	
	  //测试大整数取模
	bigint mod=num1%num2;
	cout<<"\n****测试大整数取模结果********"<<endl;
	print(mod);
	 //测试大整数乘法
	bigint multi=num1*num2;
	cout<<"\n****测试大整数乘法结果********"<<endl;
	print(multi);
	//测试扩展欧几里得求逆元
	char strd1[3]="5";
	char strd2[6]="96";
	bigint d1;
	bigint numd1=change(strd1);
	bigint numd2=change(strd2);
	d1=mod_reverse(numd1,numd2);
	cout<<"\n****测试扩展欧几里得求逆元5*e mod96结果********"<<endl;
	cout<<"d:";print(d1);
	//
	cout<<"\n****测试读取文件结果********"<<endl;
	readMyf();


	cout<<"\n****测试Quick_Power结果********"<<endl;
	cout<<"print(Quick_Power(in2,in2,in3));"<<endl;
	print(Quick_Power(in2,in2,in3));cout<<endl;

	//生成大素数
	cout<<"\n****测试生成大素数结果********"<<endl;
	cout<<"生成大素数:"<<endl;
	bigint p1 = genPrime(128);
	cout<<"p=";print(p1);


	
	char str5[2]="5";
	bigint in5=change(str5);

	
	
	
	//cout<<"5%1:";print(in5%in1);cout<<endl;
	//测试密钥生成
	initskey();



	RSA_Encrypt();
	RSA_Decrypt();

	//测试扩展欧几里得算法,用e=5,d=96
	/*bigint in5;
	in5.len=1;
	in5.d[in5.len-1]=5;
	bigint in96;
	in96.len=2;
	in96.d[in5.len-1]=9;
	in96.d[in5.len-2]=6;
	bigint ed,ey;
	//Get_e(in5,in96,ed,ey);
	ed=(ed%in96+in96)%in96;
	cout<<"d"<<endl;
	print(ed);
	*/

	//测试256进制转换

	char str[6]="65537";
	bigint in65537=change(str);
	bigint256 bin=change256(in65537);

	printb(bin);
	return 0;

}

2020.1.9:后记:这个后来用了1024bit的大整数,二进制什么的,现在我已经忘光了,记得当时网上有人家写的很好的,然后我从头到尾开始分析他代码的思想,做了个分析,然后加工加工就写报告了。

小结:关于大学里面课设的话,可能外观更重要,算法做的再好,以我现在菜鸡的水平也做不了什么,所以搞个壳子是最重要的,有了壳子之后里面的算法网上都有。

希望以后做毕设可以顺利些。

发布了68 篇原创文章 · 获赞 20 · 访问量 6859

猜你喜欢

转载自blog.csdn.net/qq_43633973/article/details/103053725