二进制方法中,只需要移位(<<和>>)和加减操作(+和-),不像欧几里德算法中需要乘法和除法运算。虽然算法效率更高,但是程序的可读性和可维护性差一些。

如果设d=gcd(u,v) = u.x + v.y, 本算法涉及到六种操作:

1)已知ext_gcd(u,v)如何求ext_gcd(u,2v)=u'.x' + v'.y',其中u为奇数,v可奇可偶,d=gcd(u,v)为奇数;

2)已知ext_gcd(u,v)如何求ext_gcd(2u,v)=u'.x' + v'.y',其中v为奇数,u可奇可偶,d=gcd(u,v)为奇数;

3)已知ext_gcd(u-v,v)如何求ext_gcd(u,v)=u'.x' + v'.y';

4)已知ext_gcd(u,u-v)如何求ext_gcd(u,v)=u'.x' + v'.y';

5)已知u/2^c = v = d(c为大于0的整数),如何求ext_gcd(u,v)=u.x' + v.y';

6)已知u= v/2^c = d(c为大于0的整数),如何求ext_gcd(u,v)=u.x' + v.y'.

其中第1)种操作比较麻烦,第2)种操作只需要在第1)种操作的基础上将u和v交换一下。下面介绍一下第1)种操作的原理:

在第1)操作中,因为d=gcd(u,2v)=gcd(u-v,v)=(u-v)x+v(x+y),设u1=u-v,x1=x,v1=v,y1=x+y,即问题转化为已知d=u1.x1+u1.y1,求ext_gcd(u,2v)=u.x' + (2v)y'=d;

如果y为偶数,显然可以采用这样一组值:x'=x,y'=y/2;但是如果y为奇数,则需要将d表示为d=u1(x1+v1.k) + v1(y1-u1.k),其中k为正奇数1,3,5....,找到这样的k,满足x' = x +v.k和y'=(y-u.k)/2都不为0。

第3)种操作比较简单,因为d=gcd(u-v,v) = (u-v)x + vt = ux + v(y-x),即x'=x,y'=y-x;

第4)种操作类似,因为d=gcd(u,u-v) = ux + (u-v)t = u(x+y) - vy,即x'=x+y,y'=-y;

第5)种操作,可以得到d=v=u + (1-2^c).v,即x'=1,y'=1-2^c;

第6)种操作只需要在第5)种操作的基础上将u和v交换一下。

在下面的实现中,只有上面第2)和6)种操作需要改变v和y的符号。

import java.util.Stack;
/*** * @author ljs 2011-5-19* * solve extended gcd using Binary Method**/
public class ExtGCD_Binary {/*** caculate x,y to satisfy Bezout Identity: u.x + v.y = gcd(u,v)* @param u* @param v* @return {d,x,y} for: d = u.x + v.y;*/public static int[] extGCDBinary(int u,int v){u=(u<0)?-u:u;v=(v<0)?-v:v;if(u==0)return new int[]{v,0,1};if(v==0)return new int[]{u,1,0};int k=0;while((u & 0x01)==0 && (v & 0x01) == 0){u>>=1; //divide by 2v>>=1;k++;}//with respect to d=gcd(u,v)=u.s+v.t/* the operation type is defined as:1: c, u / 2^c (push two numbers to stack: first push c, then push the op number 1)2: c, v / 2^c  (push two numbers to stack: first push c, then push the op number 2)3: gcd(u-v, v) (only push the op number 3 to stack)4: gcd(u, u-v) (only push the op number 4 to stack)  */Stack<Integer> ops= new Stack<Integer>();//at this time, there is at least one number is odd between m and nint t=-v; //set it negative for later comparison of (t>0)if((v & 0x01)==1){//if v is oddt = u;}//process t as a possible even numberboolean firstNoOp = true;while(t != 0){if(firstNoOp) {firstNoOp = false;}else{if(t>0)ops.push(3);elseops.push(4);}int c=0;while((t & 0x01)==0){//do until t is not even t>>=1;c++;}if(t>0) {//u > v (the max is replaced by |t|)u=t; if(c>0) {ops.push(c);  ops.push(1);      }}else{ //u<v (the max is replaced by |t|)v=-t;if(c>0){ops.push(c);   ops.push(2);}}//now u and v are all odd, then u-v is event = u-v; }int d = u;//the following steps are to caculate x,y in d=u.x + v.yint x=1,y=0;//special processing for the last operationif(!ops.isEmpty()){//e.g. for input u=3,v=3, then ops is empty, d=3int op = ops.pop();int c = ops.pop();//op number 3 and 4 can not be the last step since: u-v = v, then v is even; or u=u-v, then u=0; //both are not possible     int tmp = 1<<c;if(op == 1){                x = 1;y = 1- tmp;u = v;for(int i=0;i<c;i++)u <<= 1;             }else if(op == 2){x = 1- tmp;y = -1;v = -u;for(int i=0;i<c;i++)v <<= 1;   }}while(!ops.isEmpty()){    int op = ops.pop();switch(op){case 1:{int c = ops.pop();for(int i=0;i<c;i++){if((x & 0x01)==0){//if x is even x >>= 1;}else{y += u;int tmp = x - v;while(y ==0 || tmp ==0){y += (u<<1); //*2tmp -= (v<<1); //*2};x = tmp >>1;}u <<= 1;}break;}case 2:{                 int c = ops.pop();for(int i=0;i<c;i++){if((y & 0x01)==0){//if y is even                                y >>= 1;}else{x += v;int tmp = y-u;while(x ==0 || tmp ==0){x += (v<<1);  //*2tmp -= (u<<1);  //*2};y = tmp >>1;}v <<= 1;                     }y = -y;v = -v;break;}case 3:y -= x;u += v;break;case 4:x += y;                  v = u - v;y = -y;break;}}//e.g. gcd(1,4)y = (v<0)?-y:y;for(int i=0;i<k;i++)d <<=1;return new int[]{d,x,y};}public static void print(int m,int n,int[] extGCDResult){m = (m<0)?-m:m;n = (n<0)?-n:n;System.out.format("extended gcd of %d and %d is: %d = %d.{%d} + %d.{%d}%5s%n",m,n,extGCDResult[0],m,extGCDResult[1],n,extGCDResult[2],(m*extGCDResult[1] + n * extGCDResult[2] == extGCDResult[0])?"OK":"WRONG!!!");        }public static void main(String[] args) {int m = -18;int n= 12;print(m,n,extGCDBinary(m,n));//co-primem = 15;n= 28;print(m,n,extGCDBinary(m,n));m = 6;n= 3;print(m,n,extGCDBinary(m,n));m = 6;n= 3;print(m,n,extGCDBinary(m,n));m = 6;n= 0;print(m,n,extGCDBinary(m,n));m = 0;n= 6;print(m,n,extGCDBinary(m,n));m = 0;n= 0;print(m,n,extGCDBinary(m,n));m = 1;n= 1;print(m,n,extGCDBinary(m,n));m = 3;n= 3;print(m,n,extGCDBinary(m,n));m = 2;n= 2;print(m,n,extGCDBinary(m,n));m = 1;n= 4;print(m,n,extGCDBinary(m,n));m = 4;n= 1;print(m,n,extGCDBinary(m,n));m = 10;n= 14;print(m,n,extGCDBinary(m,n));m = 14;n= 10;print(m,n,extGCDBinary(m,n));m = 10;n= 4;print(m,n,extGCDBinary(m,n));m = 273;n= 24;print(m,n,extGCDBinary(m,n));m = 120;n= 23;print(m,n,extGCDBinary(m,n));}
}

转载于:https://www.cnblogs.com/ljsspace/archive/2011/06/05/2073367.html

经典算法(5)- 用二进制方法实现扩展的最大公约数(Extended GCD)相关推荐

  1. python人脸识别特征脸法_人脸识别经典算法一 特征脸方法(Eigenface)

    这篇文章是撸主要介绍人脸识别经典方法的第一篇,后续会有其他方法更新.特征脸方法基本是将人脸识别推向真正可用的第一种方法,了解一下还是很有必要的.特征脸用到的理论基础PCA在另一篇博客里:特征脸(Eig ...

  2. 人脸识别经典算法二:LBP方法

    LBP(Local Binary Patterns,局部二值模式)是提取局部特征作为判别依据的.LBP方法显著的优点是对光照不敏感,但是依然没有解决姿态和表情的问题.不过相比于特征脸方法,LBP的识别 ...

  3. 人脸识别经典算法:特征脸方法(Eigenface)

    https://www.toutiao.com/a6698955075127083527/ 这个算法需要数学知识特别好的人才会看得懂吧! 步骤一:获取包含M张人脸图像的集合S.在我们的例子里有25张人 ...

  4. python人脸识别特征脸法_人脸识别经典算法:特征脸方法(Eigenface)

    特征脸方法基本是将人脸识别推向真正可用的第一种方法,了解一下还是很有必要的.特征脸用到的理论基础PCA在之前的文章中已经讲过了.直接上特征脸方法的步骤: 步骤一:获取包含M张人脸图像的集合S.在我们的 ...

  5. 黑产反诈有方法,异常识别我在行—欺诈反洗钱等领域用得最多的经典算法

    样本异常值处理是建模过程数据清洗的一个比较重要环节,可以有效提升后续模型训练拟合的精准度.对于数据异常值的识别,具体实现的方法可以分为统计分析和模型算法两个维度,其中统计分析方法主要是箱线图分布.标准 ...

  6. 效率高低有方法 数据挖掘十大经典算法

    国际权威的学术组织the IEEE International Conference on Data Mining (ICDM) 2006年12月评选出了数据挖掘领域的十大经典算法:C4.5, k-M ...

  7. [论文阅读] (23)恶意代码作者溯源(去匿名化)经典论文阅读:二进制和源代码对比

    <娜璋带你读论文>系列主要是督促自己阅读优秀论文及听取学术讲座,并分享给大家,希望您喜欢.由于作者的英文水平和学术能力不高,需要不断提升,所以还请大家批评指正,非常欢迎大家给我留言评论,学 ...

  8. 前端笔试常考设计模式,操作系统,数据结构,ACM模板,经典算法,正则表达式,常用方法

    考试时允许使用草稿纸,请提前准备纸笔.考试过程中允许上厕所等短暂离开,但请控制离开时间 笔试得分60%一般通过,面试答对80%才能通过 合集:2023年最全前端面试题考点HTML5+CSS3+JS+V ...

  9. 经典算法研究系列:二、Dijkstra 算法初探

    经典算法研究系列:二.Dijkstra 算法初探  July   二零一一年一月 ====================== 本文主要参考:算法导论 第二版.维基百科. 写的不好之处,还望见谅. 本 ...

最新文章

  1. 配置Eclipse支持java和xml文件的代码补全功能
  2. Segment Routing — SRv6 — 统一的 SDN 控制面与数据面
  3. w3wp.exe内存占用过高(网站打不开,应用程序池回收就正常)
  4. 关注CIO:IT运维如何实现“向管理要效益”(转载)
  5. Pandas的学习(2.Series的索引和切片、基本概念以及Series的运算)
  6. python中for循环和while循环的区别_python中while循环和for循环的定义和详细的使用方法...
  7. EOJ_1024_表达式
  8. mybatis-plus 使用乐观锁修改
  9. 微信小程序scroll-viwe遇到的问题
  10. 软件构造 第五章第三节 可复用的设计模式
  11. 《Python cookbook》笔记一
  12. POJ 1595 素数打表水题
  13. 在B/S系统中引入定时器的功能
  14. 阿里云服务器价格表,阿里云服务器最新收费标准大全
  15. java rnn生成古诗_基于循环神经网络(RNN)的古诗生成器
  16. 蓝桥杯龟兔赛跑预测Python(超详细!!)
  17. Cisco RV340命令执行漏洞(CVE-2022-20707)及关联历史漏洞分析
  18. Silvaco TCAD仿真8——网格mesh的意义(举例说明)
  19. TiFlink: 使用 TiKV 和 Flink 实现强一致的物化视图
  20. 从DDR到DDR4,内存核心频率其实基本上就没太大的进步

热门文章

  1. 循环码差错图样matlab,基于MATLAB的(15,7)循环码的编译仿真.doc
  2. app自定义图标 vue_uniapp自定义图标组件
  3. sdn体系的三个平面_软件定义网络基础---SDN控制平面
  4. php 微信分享功能_使用php怎么实现一个微信分享朋友链接功能
  5. Linux更改显示管理器,聊聊Linux操作系统中的显示管理器及如何更换
  6. oracle 加全文索引,oracle全文索引的创建和使用
  7. java强引用软引用深刻理解_Java-强引用、软引用、弱引用、虚引用
  8. 移动app部分机型无法唤起h5支付宝支付_谜之wxs,uni-app如何用它大幅提升性能
  9. 美国无人机在火星首飞成功,创造历史,3米飞行高度悬停30秒
  10. 欧姆龙plc解密实例_西门子、施耐德、欧姆龙等13大PLC品牌8000个实例程序资料包...