MATLAB实现扩展欧几里得算法

程序下载链接:https://download.csdn.net/download/m0_56241309/87457173

实验题目:拓展欧几里得算法+求逆元

一、实验目的

实验环境: Windows 11操作系统;Matlab2019b

实现目标:实现拓展欧几里得算法;

线性组合表示最大公因子;

实现求逆元的运算;

创建交互界面;

实现关键步骤信息输出。

二、方案设计

1. 拓展欧几里得算法计算过程

  1. 拓展欧几里得算法本质上还是欧几里得算法,只是需要使用线性组合的方式表示出最大公因子

  1. 本次实验基于两个递归函数,一个时欧几里得算法求解最大公因子的递归函数gcd(),一个是拓展的欧几里得算法求解线性组合系数的函数exgcd()

  1. 创建一个全局的数组A,作为属性声明,用于存储每一步递归下的线性组合系数

  1. 每一次调用exgcd()函数,都会同步地跟新A中存储的线性组合系数A(1,1)和A(1,2)。更新方式为:

app.A(1,1)=app.A(1,2);

app.A(1,2)=temp-floor(m/n)*app.A(1,2);

  1. 此外,每次递归时需要注意交换参数的位置。即,始终确保左边的参数大于右边的参数。通过模运算的方式,即mod(m,n)的方式来确保这一点。实现这一点的语句为: exgcd(n,mod(m,n))

  1. gcd()函数与exgcd()函数同样,递归结束的条件为当参数中出现0时

  1. 递归结束后,exgcd()会返回A,A中存储了最终的线性组合系数

2. 逆元求解过程

  1. 求解逆元时,为了提高效率,不再使用递归的方式,但是整体拆分成了两大块进行处理

  1. 首先,当输入的两个数字进行模运算后,结果中出现零时,结果其中一个数字为1,则直接返回1。否则,由于两个数字本身存在公因子,因此不存在逆元

  1. 如果两个数字本身不存在公因子,则进入while循环中,循环计算直至某次运算中两个数互相模运算的结果中出现0。计算的核心部分为:

t1 = rem(u -( q * v1),m);如果t1>0,则最终的逆元就是t1,否则,最终的逆元为t1+m,确保其大于零。

3. 信息输出

  1. 设置两个信息输出函数,分别实现拓展欧几里得算法界面和求解逆元界面的信息输出

4. 交互界面

  1. 基于Matlab2019b中的mlapp编程实现

三、方案实现

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. 数据测试

  1. 拓展欧几里得算法

测试数据:963*-15+657*22=9;962*-187+537*335=1

  1. 求解逆元

测试数据:3-1 mod26=9;5-1 mod26=21; 7-1 mod26=15

  1. 计算过程演示

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的话,则加上模数,得到最终的逆元。

五、总结

  1. 拓展的欧几里得算法用于表示最大公因子,即将最大公因子使用两数的线性组合来表示

  1. 拓展的欧几里得算法核心依旧是欧几里得算法,整体上在实现时可以采用递归思想

  1. 欧几里得算法的核心就是:gcd(a,b)=gcd(b,a%b)=d

  1. 在求解最大公因子的线性组合系数时,需要不断地在递归中更新系数,因此将存储系数的数组A设置成了全局属性,A(1,1)和A(1,2)分别存储了两个数的系数,用于表示最终的最大公因子

  1. 拓展的欧几里得算法中,核心部分为app.A(1,2)=temp-floor(m/n)*app.A(1,2)以及exgcd(n,mod(m,n))。其中,exgcd(n,mod(m,n))用于在递归时确保两个参数中存在一个数大于另一个数,并且当mod(m,n)的结果为0时,结束递归

  1. 求解逆元时,并没有采用递归的方式。首先直接判断两数是否存在最大公共因子,如果存在的话则直接返回NULL,即不存在逆元。如果其中一个数字为1的话,则直接返回逆元1

  1. 求解逆元时,如果已经排除了if条件,则直接进入循环,核心部分的代码为t1 = rem(u -( q * v1),m)

  1. 最终返回逆元时,需要确保逆元大于零,因此当逆元大于零时不做处理,当逆元小于零时,则加上模数

  1. 在使用mlapp编程时,需要将最大公因子使用两数的线性组合表示,与其他编程方式中的printf输出格式不同,直接使用num2str()函数加上strcat()函数即可实现想要的输出格式

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BumbleStone

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值