版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第九讲,高精度计算,ACM算法与程序设计,2,大整数加法,1、链接地址 2、问题描述 求两个不超过200 位的非负整数的和。 输入数据 有两行,每行是一个不超过200 位的非负整数,没有多余的前导0。,3,问题描述,输出要求 一行,即相加后的结果。结果里不能有多余的前导0,即如果结果是342,那么就不能 输出为0342。 输入样例 22222222222222222222 33333333333333333333 输出样例 Output Sample: 55555555555555555555,4,首先要解决的就是存储200 位整数的问题。显然,任何C/C+固有类型的变量都无法保存它。最直观的
2、想法是可以用一个字符串来保存它。字符串本质上就是一个字符数组,因此为了编程更方便,我们也可以用数组unsigned an200来保存一个200 位的整数,让an0存放个位数,an1存放十位数,an2存放百位数 那么如何实现两个大整数相加呢?方法很简单,就是模拟小学生列竖式做加法,从个位开始逐位相加,超过或达到10 则进位。也就是说,用unsigned an1201保存第一个数,用unsigned an2200表示第二个数,然后逐位相加,相加的结果直接存放在an1 中。要注意处理进位。另外,an1 数组长度定为201,是因为两个200 位整数相加,结果可能会有201 位。 实际编程时,不一定要费
3、心思去把数组大小定得正好合适,稍微开大点也无所谓,以免不小心没有算准这个“正好合适”的数值,而导致数组小了,产生越界错误。,3、解题思路,5,4、参考程序,#include #include #define MAX_LEN 200 int an1MAX_LEN+10; int an2MAX_LEN+10; char szLine1MAX_LEN+10; char szLine2MAX_LEN+10; int main(void) scanf(%s, szLine1); scanf(%s, szLine2); int i, j; memset( an1, 0, sizeof(an1); mems
4、et( an2, 0, sizeof(an2);,6,4、参考程序,int nLen1 = strlen( szLine1); for( j = 0, i = nLen1 - 1;i = 0 ; i -) an1j+ = szLine1i - 0; int nLen2 = strlen(szLine2); for( j = 0, i = nLen2 - 1;i = 0 ; i -) an2j+ = szLine2i - 0; for( i = 0;i = 10 ) /看是否要进位 an1i -= 10; an1i+1 +; /进位 for( i = MAX_LEN; (i = 0) ,7,大整
5、数乘法,1、链接地址 2、问题描述 求两个不超过200 位的非负整数的积。输入数据有两行,每行是一个不超过200 位的非负整数,没有多余的前导0。输出要求一行,即相乘后的结果。结果里不能有多余的前导0,即如果结果是342,那么就不能输出为0342。,8,问题描述,输入样例 12345678900 98765432100 输出样例 1219326311126352690000,9,在程序中,用unsigned an1200和unsigned an2200分别存放两个乘数,用aResult400来存放积。计算的中间结果也都存在aResult中。aResult长度取400是因为两个200 位的数相乘
6、,积最多会有400 位。an10, an20, aResult0都表示个位。 计算的过程基本上和小学生列竖式做乘法相同。为编程方便,并不急于处理进位,而将进位问题留待最后统一处理。 现以 83549 为例来说明程序的计算过程。,3、解题思路,10,先算8359。59 得到45 个1,39 得到27 个10,89 得到72 个100。由于不急于处理进位,所以8359 算完后,结果如下:,3、解题思路,接下来算45。此处45 的结果代表20 个10,因此要 c1+=20,变为:,再下来算43。此处43 的结果代表12 个100,因此要 c2+= 12,变为:,11,3、解题思路,最后算 48。此处
7、48 的结果代表 32 个1000,因此要 c3+= 32,变为:,乘法过程完毕。接下来从 c0开始向高位逐位处理进位问题。c0留下5,把4 加到c1上,c1变为51 后,应留下1,把5 加到c2上最终使得c 里的每个元素都是1 位数,结果就算出来了:,规律:一个数的第i 位和另一个数的第j 位相乘所得的数,一定是要累加到结果的第i+j 位上。这里i, j 都是从右往左,从0 开始数。,12,4、参考程序,#include #include #define MAX_LEN 200 int main(void) int i, j; int len1,len2; int aMAX_LEN+10,b
8、MAX_LEN+10,cMAX_LEN*2+10; char str1MAX_LEN+10,str2MAX_LEN+10; for(i=0;i=0; i-)/把数字倒过来 aj+=str1i-0; len2=strlen(str2); for(j=0,i=len2-1; i=0; i-)/倒转第二个整数 bj+=str2i-0;,13,4、参考程序,for(i=0; i=10) ci+1+=ci/10; ci%=10; for(i=MAX_LEN*2; (ci=0) ,14,大整数除法,1、链接地址 2、问题描述 求两个大的正整数相除的商 输入数据 第1 行是测试数据的组数n,每组测试数据占2
9、 行,第1 行是被除数,第2 行是除数。每组测试数据之间有一个空行,每行数据不超过100 个字符 输出要求 n 行,每组测试数据有一行输出是相应的整数商,15,问题描述,输入样例 3 2405337312963373359009260457742057439230496493930355595797660791082739646 2987192585318701752584429931160870372907079248971095012509790550883793197894 10000000000000000000000000000000000000000 10000000000 540
10、9656775097850895687056798068970934546546575676768678435435345 1 输出样例 0 1000000000000000000000000000000 5409656775097850895687056798068970934546546575676768678435435345,16,基本的思想是反复做减法,看看从被除数里最多能减去多少个除数,商就是多少。一个一个减显然太慢,如何减得更快一些呢?以7546 除以23 为例来看一下:开始商为0。先减去23 的100 倍,就是2300,发现够减3 次,余下646。于是商的值就增加300。然后用
11、646 减去230,发现够减2 次,余下186,于是商的值增加20。最后用186 减去23,够减8 次,因此最终商就是328。 所以本题的核心是要写一个大整数的减法函数,然后反复调用该函数进行减法操作。 计算除数的10 倍、100 倍的时候,不用做乘法,直接在除数后面补0 即可。,3、解题思路,17,4、参考程序,#include #include #define MAX_LEN 200 char szLine1MAX_LEN + 10; char szLine2MAX_LEN + 10; int an1MAX_LEN + 10; /被除数, an10对应于个位 int an2MAX_LEN
12、+ 10; /除数, an20对应于个位 int aResultMAX_LEN + 10; /存放商,aResult0对应于个位 /长度为 nLen1 的大整数p1 减去长度为nLen2 的大整数p2 /结果放在p1 里,返回值代表结果的长度 /如不够减返回-1,正好减完返回 0 int Substract( int * p1, int * p2, int nLen1, int nLen2) int i; if( nLen1 nLen2 ) return -1;,18,4、参考程序,/下面判断p1 是否比p2 大,如果不是,返回-1 if( nLen1 = nLen2 ) for( i = n
13、Len1-1; i=0; i - ) if( p1i p2i ) break; /p1p2 else if( p1i =nLen2 时,p2i 0 p1i -= p2i; if( p1i = 0 ; i- ) if( p1i )/找到最高位第一个不为0 return i + 1; return 0;/全部为0,说明两者相等 ,19,4、参考程序,int main() int t, n; scanf(%d, ,20,4、参考程序,int nTimes = nLen1 - nLen2; if(nTimes 0) for( i = nLen1 -1; i = nTimes; i - ) an2i =
14、 an2i-nTimes;/朝高位移动 for( ; i = 0; i-)/低位补0 an2i = 0; nLen2 = nLen1; for( j = 0 ; j = 0) nLen1 = nTmp; aResultnTimes-j+; /每成功减一次,则将商的相应位加1 ,21,4、参考程序,/下面输出结果,先跳过高位0 for( i = MAX_LEN ; (i = 0) ,22,麦森数,1、链接地址 2、问题描述 形如2P-1 的素数称为麦森数,这时P 一定也是个素数。但反过来不一定,即如果P 是个素数。2P-1 不一定也是素数。麦森数有许多重要应用,它与完全数完全数(又称完备数,是一
15、些特殊的自然数。它所有的真因子(即除了自身以外的约数)的和恰好等于它本身。)密切相关. 你的任务:输入P (1000P3100000) , 计算2p-1 的位数和最后500 位数字(用十进制高精度数表示),23,问题描述,输入数据 只包含一个整数P(1000P3100000) 输出要求 第1 行:十进制高精度数2p-1 的位数。 第2-11 行:十进制高精度数2p-1 的最后500位数字。(每行输出50 位,共输出10 行,不足500 位时高位补0) 不必验证2p-1 与P 是否为素数。 输入样例 1279,24,问题描述,输出样例 386 00000000000000000000000000
16、000000000000000000000000 00000000000000000000000000000000000000000000000000 00000000000000104079321946643990819252403273640855 38615262247266704805319112350403608059673360298012 23944173232418484242161395428100779138356624832346 49081399066056773207629241295093892203457731833496 61583550472959420547
17、689811211693677147548478866962 50138443826029173234888531116082853841658502825560 46662248318909188018470682222031405210266984354887 32958028878050869736186900714720710555703168729087,25,第一个问题,输出2p-1 有多少位。由于2p 的个位数只可能是2, 4, 6, 8 所以2p-1 和2p的位数相同。使用C/C+标准库中在math.h 里声明的,求以10为底的对数的函数double log10(double
18、x) 函数,就能轻松求得2p-1 的位数。 2p 的值需要用一种高效率的办法来算。 显然,对于任何p0,考虑p 的二进制形式,则不难得到: 这里,ai 要么是1,要么是0。,3、解题思路,26,因而: 计算2p 的办法就是:先将结果的值设为1,计算21。如果a0 值为1,则结果乘以21;计算22,如果a1 为1,则结果乘以22;计算24,如果a2 为1,则结果乘以24;总之,第i 步(i 从0 到n,an 是1)就计算22i,如果ai 为1,则结果就乘以22i。每次由22i22i就能算出22(i+1)。由于p可能很大,所以上面的乘法都应该使用高精度计算。由于题目只要求输出500 位,所以这些乘
19、法都是只须算出末尾的500 即可。,3、解题思路,27,在前面的高精度计算中,我们用数组来存放大整数,数组的一个元素对应于十进制大整数的一位。本题如果也这样做,就会超时。为了加快计算速度,可以用一个数组元素对应于大整数的4 位,即将大整数表示为10000 进制,而数组中的每一个元素就存放10000 进制数的1 位。例如,用int 型数组 a 来存放整数6373384,那么只需两个数组元素就可以了,a0=3384, a1=637。 由于只要求结果的最后500 位数字,所以我们不需要计算完整的结果,只需算出最后500 位即可。因为用每个数组元素存放十进制大整数的4 位,所以本题中的数组最多只需要1
20、25 个元素。,3、解题思路,28,4、参考程序,#include #include #define LEN 125 /每数组元素存放4 位,数组最多需要125 个元素 #include /计算高精度乘法 a * b, 结果的末500 位放在a 中 void Multiply(int* a, int* b) int i, j; int nCarry; /存放进位 int nTmp; int cLEN; /存放结果的末500 位 memset(c, 0, sizeof(int) * LEN); for (i=0;iLEN;i+) nCarry=0; for (j=0;jLEN-i;j+) nTm
21、p=ci+j+aj*bi+nCarry; ci+j=nTmp%10000; nCarry=nTmp/10000; memcpy( a, c, LEN*sizeof(int); ,29,4、参考程序,int main(void) int i; int p; int anPowLEN; /存放不断增长的2 的次幂 int aResultLEN; /存放最终结果的末500 位 scanf(%d, ,30,4、参考程序,aResult0-; /2p-1 /输出结果 for (i=LEN-1;i=0;i-) if (i%25=12) printf(%02dn%02d, aResulti/100, aRe
22、sulti%100); else printf(%04d, aResulti); if (i%25=0) printf(n); return 0; ,31,练习:Exponentiation,Description (POJ:1001) Problems involving the computation of exact values of very large magnitude and precision are common. For example, the computation of the national debt is a taxing experience for many computer systems. This problem requires that you write a program to compute the exact value of Rn where R is a real number ( 0.0 R 99.999 ) and n is an integer such that 0 n = 25.,32,Description,Input The input will consist of a set of pairs of values for R and n. The R value will occu
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026中科华轨航空产业发展(天津)有限公司招聘6人笔试备考试题及答案解析
- 2026年驻马店上蔡县事业单位引进高层次人才59名笔试参考题库及答案解析
- 2026广东阳江市阳春市统计局招聘合同制工作人员1人考试备考题库及答案解析
- 2026重庆沙坪坝区渝碚路社区卫生服务中心招聘1人笔试备考试题及答案解析
- 培训会议奖罚制度
- 培训学校学生培训制度
- 培训班教师惩罚制度
- 培训机构采购制度
- 驾校岗前培训制度
- 培训学生办事制度
- 2026年陕西省森林资源管理局局属企业公开招聘工作人员备考题库及参考答案详解1套
- 承包团建烧烤合同范本
- 电力线通信技术
- 人工流产手术知情同意书
- 2025秋人教版七年级全一册信息科技期末测试卷(三套)
- 教师三笔字培训课件
- 钢铁烧结机脱硫脱硝施工方案
- 中国医药行业中间体出口全景分析:破解政策难题深挖全球红利
- 抢工补偿协议书
- 英语A级常用词汇
- 协调控制系统
评论
0/150
提交评论