三、方案实现 1. 拓展欧几里得算法过程 介绍:gcd回调函数 function results = gcd(app,a,b)
ifb==0
results=a;
else
results=app.gcd(b,mod(a,b));
end
end
介绍:exgcd回调函数 function result=exgcd(app,m,n)
ifn==0
app.A(1,1)=1;
app.A(1,2)=0;
result=m;
else
r=app.exgcd(n,mod(m,n));
temp=app.A(1,1);
app.A(1,1)=app.A(1,2);
app.A(1,2)=temp-floor(m/n)*app.A(1,2);
result=r;
end
end
介绍:CFBButton回调函数-线性组合表示最大公因子 function CFBButtonPushed(app, event)
ifapp.NUM1.Value==0&&app.NUM2.Value==0
logRefresh_func(app,'请至少输入一个非零整数');
return
end
m=app.NUM1.Value;
n=app.NUM2.Value;
%最大公因子
d=app.exgcd(m,n);
c=app.gcd(m,n);
k=c/d;
if(k*app.A(1,2)>0)
app.CFE.Value=strcat(num2str(m),'*',num2str(k*app.A(1,1)),'+',num2str(n),'*',num2str(k*app.A(1,2)),'=',num2str(c));
else
app.CFE.Value=strcat(num2str(m),'*',num2str(k*app.A(1,1)),num2str(k*app.A(1,2)),'*',num2str(n),'=',num2str(c));
end
app.logRefresh_func('求解成功')
end
2. 求解逆元 介绍:NiYuanBButton回调函数 function NiYuanBButtonPushed(app, event)
ifapp.NUM.Value==0||app.MO.Value==0
logRefresh_func_Niyuan(app,'请输入非零整数');
return
end
u=1;%%u=1,g=a,v1=0,v3=m
a=app.MO.Value;
g=a;
v1=0;
m=app.NUM.Value;
v3=m;
q=int16(g/v3);%%计算q=g/v3,t3=g%v3
t3=mod(g,v3);
if(t3 == 0)%%如果t3等于0则直接执行以下判断
g=v3;
if(g == 1)
if(v1 > 0)
app.EditField.Value=num2str(v1);
else
app.EditField.Value=num2str(v1+m);
end
else
app.EditField.Value='NULL';
end
else
while(true)%%如果t3不等于0,则进行循环计算直至t3等于0
t1=rem(u -(q*v1),m);%%计算t1=(u-q*v1)modm,u=v1,g=v3,v1=t1,v3=t3
u=v1;
g=v3;
v1=t1;
v3=t3;
q=floor(g/v3);
t3=rem(g,v3);
if(t3 == 0)
g=v3;
if(g == 1)%%如果g=1,
if(v1 > 0)%%当v1>0时返回v1,否则返回m+v1
% app.NIYUAN.Value=v1;
app.EditField.Value=num2str(v1);
break;
else
% app.NIYUAN.Value=m+v1;
app.EditField.Value=num2str(v1+m);
break;
end
else%%g不等于1时返回乘法逆元不存在
% app.NIYUAN.Value=0;
app.EditField.Value='NULL';
break;
end
end
end
end
logRefresh_func_Niyuan(app,'求解成功');
end
3. 信息输出 介绍:加密界面信息输出函数logRefresh_func function logRefresh_func(app,StrArrayNew)
app.Ptime=datestr(now);
app.LOG=strcat('[',app.Ptime(end-7:end),']');
StrArrayNew=strcat(app.LOG,StrArrayNew);
app.StrArray_En=[app.StrArray_En,StrArrayNew,newline];
app.Process.Value=app.StrArray_En;
end
介绍:求解逆元界面信息输出函数logRefresh_func_Niyuan function logRefresh_func_Niyuan(app,StrArrayNew)
app.Ptime=datestr(now);
app.LOG=strcat('[',app.Ptime(end-7:end),']');
StrArrayNew=strcat(app.LOG,StrArrayNew);
app.StrArray_De=[app.StrArray_De,StrArrayNew,newline];
app.Process_Niyuan.Value=app.StrArray_De;
end
4. 交互界面 Matlab2019b的mlapp开发环境
|
四、数据测试与分析 1. 数据测试
拓展欧几里得算法
测试数据:963*-15+657*22=9;962*-187+537*335=1
求解逆元
测试数据:3-1 mod26=9;5-1 mod26=21; 7-1 mod26=15
计算过程演示
2. 分析
实验中,为了实现使用拓展欧几里得算法表示最大公因子,创建了两个递归函数,一个是用于求解最大公因子的gcd()函数,一个是用于求解线性组合系数的exgcd()函数。调用gcd()函数可以计算得出两数的最大公因子。调用exgcd()函数可以返回最大公因子的线性组合。需要注意的是,为了可以在递归过程中不断更新因子的线性组合系数,在属性中初始化了数组A用于存储最大公因子的线性组合系数。更新方式为: app.A(1,1)=app.A(1,2); app.A(1,2)=temp-floor(m/n)*app.A(1,2); 此外,每次递归时需要注意交换参数的位置。即,始终确保左边的参数大于右边的参数。通过模运算的方式,即mod(m,n)的方式来确保这一点。实现这一点的语句为: exgcd(n,mod(m,n))。递归结束后,exgcd()返回A,A中存储了最终的线性组合系数,即A(1,1)和A(1,2)。
求解逆元时,不在采用递归的方式,但是在总体上还是需要进行while循环,并借助条件判断是否结束循环。当获取输入后,首先判断二者是否存在最大公因子,如果存在公因子的化,则可以直接判断不存在逆元。如果输入的数中存在1,则可直接返回逆元1。如果都不满足,则可以进入while循环。循环直至模运算的结果中出现了0.计算的核心部分为t1 = rem(u -( q * v1),m)。最终返回逆元时,需要确保其大于0,如果小于0的话,则加上模数,得到最终的逆元。 |