大数乘法
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
•
BY WFSUN
注:这曾是某知名软件公司曾经频繁出现的面试题目
大数乘法、递归 2/12
常用方法
• 循环法 特点:从笔算算法中提出,思想相对简单,但位数较大时, 特点:从笔算算法中提出,思想相对简单,但位数较大时, 乘法次数多, 乘法次数多,效率较低 • 分治递归法 特点:采用分治递归思想,较常规方法复杂, 特点:采用分治递归思想,较常规方法复杂,但位数较大时 乘法次数少, ,乘法次数少,效率相对高
BY WFSUN
10/12
• List* rev( List * head )
{ List *rHead;
BY WFSUN
if( !head ) { return head; } else if( !head->next ) //只有一个结点 只有一个结点 { return head; } else {rHead = rev( head->next ); head->next->next = head; head->next = NULL; return rHead; } 大数乘法、递归 } 11/12
BY WFSUN
大数乘法、递归
3/12
循环法
• 基本思想:将待相乘大整数存入字符串中,按位存入 基本思想:将待相乘大整数存入字符串中, 较大的数组,循环按位相乘并累加。 较大的数组,循环按位相乘并累加。最后将进位分离 并加到相邻高位上。 最后一行? 并加到相邻高位上。 (P87 最后一行?) • 主要函数: 主要函数: GetDigits(int*a,char*s) 将字符串形式的数据按 ( , ) 位存入整型数组中 Multiply(int *a,int *b,int *c) 按位实现乘法运算,将 按位实现乘法运算, a*b的结果存入数组 中 的结果存入数组c中 的结果存入数组
数据结构与算法 For 软件学院09级本科生 2010-2011秋 软件学院09级本科生 2010-2011秋
大整数乘法,递归
孙伟峰
问题描述
• 计算机硬件所能表示的数字位数有限。 计算机硬件所能表示的数字位数有限。 在有些情况下, 在有些情况下,我们要处理很大的整数 ,它无法在计算机硬件能直接表示的范 围内进行处理。 因此, 围内进行处理。 因此,需要有效的算法 来实现大整数运算。 来实现大整数运算。 • 请设计一个有效的算法,可以进行两个 请设计一个有效的算法, 任意位大整数的乘法运算。 任意位大整数的乘法运算。
BY WFSUN
大数乘法、递归
(2)
8/12
分治递归法
要想改进算法的计算复杂性,必须减少乘法次数。 要想改进算法的计算复杂性,必须减少乘法次数。为 此我们把XY写成另一种形式 写成另一种形式: 此我们把 写成另一种形式
XY=AC*2^n+[(A-B)(DC)+AC+BD]2^n/2+BD
(3)
虽然,式(3)看起来比式 复杂些,但它仅需做 次 看起来比式(1)复杂些 虽然, 看起来比式 复杂些,但它仅需做3次 n/2位整数的乘法 位整数的乘法(AC,BD和(A-B)(D-C)),6次加、 次加、 位整数的乘法 , 和 , 次加 减法和2次移位 由此可得: 次移位。 减法和 次移位。由此可得
//先将结果数组设置 先将结果数组设置
ห้องสมุดไป่ตู้
//逐位乘法的实现 逐位乘法的实现
// 处理进位
}
BY WFSUN
大数乘法、递归
6/12
分治递归法
• 基本思想: 基本思想: 都是n位的 设X和Y都是 位的二进制(注1)整数,现在要计算它们的 和 都是 位的二进制 )整数, 乘积XY。 乘积 。 我们将n位的二进制整数 位的二进制整数X和 各分为 各分为2段 我们将 位的二进制整数 和Y各分为 段,每段的长为 n/2位(注2),如图所示。 位 ) 如图所示。
(4) 用解递归方程的套用公式法马上可得其解为 T(n)=O(n*log3)=O(n*1.59)。 。
大数乘法、递归
BY WFSUN
9/12
分治递归法伪代码
• • function MULT(X,Y,n); {X和Y为2个小于 的整数,返回结果为 和 个小于2n的整数 , , 和 为 个小于 的整数,返回结果为X和 Y的乘积 的乘积XY} 的乘积 begin S:=SIGN(X)*SIGN(Y); {S为X和Y的符号乘积 的符号乘积} 为 和 的符号乘积 X:=ABS(X); Y:=ABS(Y); {X和Y分别取绝对值 分别取绝对值} 和 分别取绝对值 if n=1 then if (X=1)and(Y=1) then return(S) else return(0) else begin A:=X的左边 的左边n/2位; 的左边 位 B:=X的右边 的右边n/2位; 的右边 位 C:=Y的左边 的左边n/2位; 的左边 位 D:=Y的右边 的右边n/2位; 的右边 位 ml:=MULT(A,C,n/2); m2:=MULT(A-B,D-C,n/2); m3:=MULT(B,D,n/2); S:=S*(m1*2n+(m1+m2+m3)*2n/2+m3); return(S); end; end; 大数乘法、递归
•
有报告显示,从大于600位的整数开始 分治法的性能超越了笔算算法的性能 位的整数开始,分治法的性能超越了笔算算法的性能 注:有报告显示,从大于 位的整数开始 分治法的性能超越了笔算算法的性能. 如果我们使用类似Java、C++和Smalltalk这样的面向对象语言,会发现这些语言专门为 这样的面向对象语言, 如果我们使用类似 、 和 这样的面向对象语言 处理大整数提供了一些类。 处理大整数提供了一些类。
由此, 的乘积为: 由此,X=A*2^n/2+B ,Y=C*2^n/2+D。这样,X和Y的乘积为 。这样, 和 的乘积为
XY=(A*2^n/2+B)(C*2^n/2+D)=AC*2^n+(AD+CB)*2^n/2+BD
十进制同, 注:1.十进制同,为方便取二进制介绍 十进制同
2.为简单起见,假设n是2的幂 为简单起见,假设 是 的幂 为简单起见 BY WFSUN
12/12
(1)
大数乘法、递归
7/12
分治递归法
如果按式(1)计算 如果按式 计算XY 计算 我们必须进行4次 位整数的乘法--AC,AD,BC和 我们必须进行 次n/2位整数的乘法 位整数的乘法 , , 和 BD, 以及3次不超过 位的整数加法--分别对应于式 次不超过n位的整数加法 分别对应于式(1)中的 以及 次不超过 位的整数加法 分别对应于式 中的 加号 此外还要做2次移位 分别对应于式(1)中乘 次移位--分别对应于式 中乘2^n和乘 此外还要做 次移位 分别对应于式 中乘 和乘 2^n/2。 。 所有这些加法和移位共用O(n)步运算。 步运算。 所有这些加法和移位共用 步运算 位整数相乘所需的运算总数, 设T(n)是2个n位整数相乘所需的运算总数,则由式 是 个 位整数相乘所需的运算总数 则由式(1) 我们有: ,我们有
BY WFSUN
大数乘法、递归
4/12
主要函数示例
/*把字符串形式的数字按位存放到数组 把字符串形式的数字按位存放到数组*/ 把字符串形式的数字按位存放到数组 void GetDigits(int *a, char *s) { int i; char digit; int len=strlen(s); for(i=0;i<N;i++) //数组初始化 数组初始化 *(a+i)=0; for(i=0;i<len;i++) //分离各位 分离各位 { digit=*(s+i); *(a+len-1-i) = digit - '0'; } }
BY WFSUN
• list_node* p = phead->next; • if(p == NULL || p->next == NULL) return; • list_node* p1=p->next; • p->next=NULL; • while(p1!=NULL) • { p = p1->next; • p1->next = phead->next; • phead->next = p1; • p1 = p; 大数乘法、递归 • } }
BY WFSUN
大数乘法、递归
5/12
主要函数示例
/*把a*b的结果存储到数组 中,按位表示 把 的结果存储到数组c中 按位表示*/ 的结果存储到数组 void multiply(int *a,int *b,int *c) { int i,j; for(i=0;i<N*2;i++) 为0 *(c+i)=0; for(i=0;i<N;i++) for(j=0;j<N;j++) *(c+i+j)+=*(a+i) * *(b+j); for(i=0;i<N*2-1;i++) { *(c+i+1)+=*(c+i)/10; *(c+i)=*(c+i)%10; }
BY WFSUN
注:这曾是某知名软件公司曾经频繁出现的面试题目
大数乘法、递归 2/12
常用方法
• 循环法 特点:从笔算算法中提出,思想相对简单,但位数较大时, 特点:从笔算算法中提出,思想相对简单,但位数较大时, 乘法次数多, 乘法次数多,效率较低 • 分治递归法 特点:采用分治递归思想,较常规方法复杂, 特点:采用分治递归思想,较常规方法复杂,但位数较大时 乘法次数少, ,乘法次数少,效率相对高
BY WFSUN
10/12
• List* rev( List * head )
{ List *rHead;
BY WFSUN
if( !head ) { return head; } else if( !head->next ) //只有一个结点 只有一个结点 { return head; } else {rHead = rev( head->next ); head->next->next = head; head->next = NULL; return rHead; } 大数乘法、递归 } 11/12
BY WFSUN
大数乘法、递归
3/12
循环法
• 基本思想:将待相乘大整数存入字符串中,按位存入 基本思想:将待相乘大整数存入字符串中, 较大的数组,循环按位相乘并累加。 较大的数组,循环按位相乘并累加。最后将进位分离 并加到相邻高位上。 最后一行? 并加到相邻高位上。 (P87 最后一行?) • 主要函数: 主要函数: GetDigits(int*a,char*s) 将字符串形式的数据按 ( , ) 位存入整型数组中 Multiply(int *a,int *b,int *c) 按位实现乘法运算,将 按位实现乘法运算, a*b的结果存入数组 中 的结果存入数组c中 的结果存入数组
数据结构与算法 For 软件学院09级本科生 2010-2011秋 软件学院09级本科生 2010-2011秋
大整数乘法,递归
孙伟峰
问题描述
• 计算机硬件所能表示的数字位数有限。 计算机硬件所能表示的数字位数有限。 在有些情况下, 在有些情况下,我们要处理很大的整数 ,它无法在计算机硬件能直接表示的范 围内进行处理。 因此, 围内进行处理。 因此,需要有效的算法 来实现大整数运算。 来实现大整数运算。 • 请设计一个有效的算法,可以进行两个 请设计一个有效的算法, 任意位大整数的乘法运算。 任意位大整数的乘法运算。
BY WFSUN
大数乘法、递归
(2)
8/12
分治递归法
要想改进算法的计算复杂性,必须减少乘法次数。 要想改进算法的计算复杂性,必须减少乘法次数。为 此我们把XY写成另一种形式 写成另一种形式: 此我们把 写成另一种形式
XY=AC*2^n+[(A-B)(DC)+AC+BD]2^n/2+BD
(3)
虽然,式(3)看起来比式 复杂些,但它仅需做 次 看起来比式(1)复杂些 虽然, 看起来比式 复杂些,但它仅需做3次 n/2位整数的乘法 位整数的乘法(AC,BD和(A-B)(D-C)),6次加、 次加、 位整数的乘法 , 和 , 次加 减法和2次移位 由此可得: 次移位。 减法和 次移位。由此可得
//先将结果数组设置 先将结果数组设置
ห้องสมุดไป่ตู้
//逐位乘法的实现 逐位乘法的实现
// 处理进位
}
BY WFSUN
大数乘法、递归
6/12
分治递归法
• 基本思想: 基本思想: 都是n位的 设X和Y都是 位的二进制(注1)整数,现在要计算它们的 和 都是 位的二进制 )整数, 乘积XY。 乘积 。 我们将n位的二进制整数 位的二进制整数X和 各分为 各分为2段 我们将 位的二进制整数 和Y各分为 段,每段的长为 n/2位(注2),如图所示。 位 ) 如图所示。
(4) 用解递归方程的套用公式法马上可得其解为 T(n)=O(n*log3)=O(n*1.59)。 。
大数乘法、递归
BY WFSUN
9/12
分治递归法伪代码
• • function MULT(X,Y,n); {X和Y为2个小于 的整数,返回结果为 和 个小于2n的整数 , , 和 为 个小于 的整数,返回结果为X和 Y的乘积 的乘积XY} 的乘积 begin S:=SIGN(X)*SIGN(Y); {S为X和Y的符号乘积 的符号乘积} 为 和 的符号乘积 X:=ABS(X); Y:=ABS(Y); {X和Y分别取绝对值 分别取绝对值} 和 分别取绝对值 if n=1 then if (X=1)and(Y=1) then return(S) else return(0) else begin A:=X的左边 的左边n/2位; 的左边 位 B:=X的右边 的右边n/2位; 的右边 位 C:=Y的左边 的左边n/2位; 的左边 位 D:=Y的右边 的右边n/2位; 的右边 位 ml:=MULT(A,C,n/2); m2:=MULT(A-B,D-C,n/2); m3:=MULT(B,D,n/2); S:=S*(m1*2n+(m1+m2+m3)*2n/2+m3); return(S); end; end; 大数乘法、递归
•
有报告显示,从大于600位的整数开始 分治法的性能超越了笔算算法的性能 位的整数开始,分治法的性能超越了笔算算法的性能 注:有报告显示,从大于 位的整数开始 分治法的性能超越了笔算算法的性能. 如果我们使用类似Java、C++和Smalltalk这样的面向对象语言,会发现这些语言专门为 这样的面向对象语言, 如果我们使用类似 、 和 这样的面向对象语言 处理大整数提供了一些类。 处理大整数提供了一些类。
由此, 的乘积为: 由此,X=A*2^n/2+B ,Y=C*2^n/2+D。这样,X和Y的乘积为 。这样, 和 的乘积为
XY=(A*2^n/2+B)(C*2^n/2+D)=AC*2^n+(AD+CB)*2^n/2+BD
十进制同, 注:1.十进制同,为方便取二进制介绍 十进制同
2.为简单起见,假设n是2的幂 为简单起见,假设 是 的幂 为简单起见 BY WFSUN
12/12
(1)
大数乘法、递归
7/12
分治递归法
如果按式(1)计算 如果按式 计算XY 计算 我们必须进行4次 位整数的乘法--AC,AD,BC和 我们必须进行 次n/2位整数的乘法 位整数的乘法 , , 和 BD, 以及3次不超过 位的整数加法--分别对应于式 次不超过n位的整数加法 分别对应于式(1)中的 以及 次不超过 位的整数加法 分别对应于式 中的 加号 此外还要做2次移位 分别对应于式(1)中乘 次移位--分别对应于式 中乘2^n和乘 此外还要做 次移位 分别对应于式 中乘 和乘 2^n/2。 。 所有这些加法和移位共用O(n)步运算。 步运算。 所有这些加法和移位共用 步运算 位整数相乘所需的运算总数, 设T(n)是2个n位整数相乘所需的运算总数,则由式 是 个 位整数相乘所需的运算总数 则由式(1) 我们有: ,我们有
BY WFSUN
大数乘法、递归
4/12
主要函数示例
/*把字符串形式的数字按位存放到数组 把字符串形式的数字按位存放到数组*/ 把字符串形式的数字按位存放到数组 void GetDigits(int *a, char *s) { int i; char digit; int len=strlen(s); for(i=0;i<N;i++) //数组初始化 数组初始化 *(a+i)=0; for(i=0;i<len;i++) //分离各位 分离各位 { digit=*(s+i); *(a+len-1-i) = digit - '0'; } }
BY WFSUN
• list_node* p = phead->next; • if(p == NULL || p->next == NULL) return; • list_node* p1=p->next; • p->next=NULL; • while(p1!=NULL) • { p = p1->next; • p1->next = phead->next; • phead->next = p1; • p1 = p; 大数乘法、递归 • } }
BY WFSUN
大数乘法、递归
5/12
主要函数示例
/*把a*b的结果存储到数组 中,按位表示 把 的结果存储到数组c中 按位表示*/ 的结果存储到数组 void multiply(int *a,int *b,int *c) { int i,j; for(i=0;i<N*2;i++) 为0 *(c+i)=0; for(i=0;i<N;i++) for(j=0;j<N;j++) *(c+i+j)+=*(a+i) * *(b+j); for(i=0;i<N*2-1;i++) { *(c+i+1)+=*(c+i)/10; *(c+i)=*(c+i)%10; }