高精度计算解析

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

参考程序: #include <stdio.h> #include <string.h> #define MAX_LEN 200 unsigned an1[MAX_LEN+10]; unsigned an2[MAX_LEN+10]; unsigned aResult[MAX_LEN * 2 + 10]; char szLine1[MAX_LEN+10]; char szLine2[MAX_LEN+10]; int main() { gets( szLine1); //gets函数读取一行 gets( szLine2); int i, j; int nLen1 = strlen( szLine1); memset( an1, 0, sizeof(an1)); memset( an2, 0, sizeof(an2)); memset( aResult, 0, sizeof(aResult)); j = 0; for( i = nLen1 - 1;i >= 0 ; i --) { an1[j++] = szLine1[i] - '0'; }
bStartOutput = true;
}
思考题 7.2:上面程序中,被执行次数最多的语句是哪一条?会被执行多少次?
3 大整数除法
问题描述 求两个大的正整数相除的商 输入数据 第1行是测试数据的组数n,每组测试数据占2行,第1行是被除数,第2行是除数。每组测 试数据之间有一个空行,每行数据不超过100个字符 输出要求 n行,每组测试数据有一行输出是相应的整数商 输入样例 3 2405337312963373359009260457742057439230496493930355595797660791082739 646 2987192585318701752584429931160870372907079248971095012509790550883793 197894 10000000000000000000000000000000000000000 10000000000 5409656775097850895687056798068970934546546575676768678435435345 1 输出样例 0 1000000000000000000000000000000 5409656775097850895687056798068970934546546575676768678435435345
输入样例 22222222222222222222 33333333333333333333 输出样例 Output Sample: 55555555555555555555
几个需要考虑的问题: 1、如何存储大整数? 数组
a9 a8 a7 a6 a5 a4 a3 a2 a1 a0Fra Baidu bibliotek
6 6 8 3 6 2 2 0 1 3
第六讲 高精度计算
王涛春
C/C++中的int类型能表示的范围一般是-231-231 – 1。 unsigned 类型能表示的范围是 0 -232 – 1,即 0 - 4294967295。所以,int和unsigned类型变量,都不能保存 超过10位的整数。
如果有一个长度为100位的大整数,我们如何存储?
我们如何进行大整数的运算?比如如何计算两个100位整 数的和?
1 大整数加法
问题描述 求两个不超过200位的非负整数的和。
输入数据 有两行,每行是一个不超过200位的非负整数,没有多余的前导0。
输出要求 一行,即相加后的结果。结果里不能有多余的前导0,即如果结果 是342,那么就不能输出为0342。
int nLen2 = strlen(szLine2); j = 0; for( i = nLen2 - 1;i >= 0 ; i --) { an2[j++] = szLine2[i] - '0'; }
for( i = 0;i < nLen2; i ++ ) { //每一轮都用an2的一位,去和an1各位相乘 //从an1的个位开始 for( j = 0; j < nLen1; j ++ ) //用选定的an2的那一位,去乘an1的各位 aResult[i+j] += an2[i]*an1[j]; //两数第i, j位相乘,累加到结果的第i+j位 } //下面的循环统一处理进位问题 for( i = 0; i < MAX_LEN * 2; i ++ ) { if( aResult[i] >= 10 ) { aResult[i+1] += aResult[i] / 10; aResult[i] %= 10; } } //下面输出结果 bool bStartOutput = false; for( i = MAX_LEN * 2; i >= 0; i -- ) if( bStartOutput) printf("%d", aResult[i]); else if( aResult[i] ) { printf("%d", aResult[i]); if(! bStartOutput ) printf("0"); return 0; }
所以本题的核心是要写一个大整数的减法函数,然后反复调用该函 数进行减法操作。
计算除数的10倍、100倍的时候,不用做乘法,直接在除数后面补 0即可。
参考程序
大整数除法
常见问题
1、忘了针对每一组测试数据,都要先将an1, an2和aResult初始 化成全0,而是一共只初始化了一次。这导致从第二组测试数据开 始就都不对了。 2、减法处理借位的时候,容易忽略连续借位的情况,比如 10000 – 87,借位会一直进行到1。
for( i = nLen1 - 1;i >= 0 ; i --) { an1[j++] = szLine1[i] - '0'; } int nLen2 = strlen(szLine2); j = 0; for( i = nLen2 - 1;i >= 0 ; i --) { an2[j++] = szLine2[i] - '0'; } for( i = 0;i < MAX_LEN ; i ++ ) { an1[i] += an2[i]; //逐位相加 if( an1[i] >= 10 ) //看是否要进位 { an1[i] -= 10; an1[i+1] ++; } } bool bStartOutput = false; //此变量用于跳过多余的0 for( i = MAX_LEN; i >= 0; i -- ) { if( bStartOutput) printf("%d", an1[i]); //如果多余的0已经都跳过,则输出 else if( an1[i] ) { printf("%d", an1[i]); bStartOutput = true; //碰到第一个非0的值,就说明多余的0已经都跳过 } } return 0; }
几个需要考虑的问题: 1、存储结果的数组长度应该是多少? 400
2、如何处理进位? 不急于进位,等最后统一处理
现以 835×49为例来说明程序的计算过程。 先算835×9。5×9得到45个1,3×9得到27个10,8×9得到72个100。由于不急于处理 进位,所以835×9算完后,aResult如下:
2、如何实现加法? 逐位相加 3、如何处理进位? 向数组的高位进位
+
1 1
4 5 0 9 6 3 8 7 6 7
10 11 1 8 9 12 12 5 10 3 2 6 0 7 7 7 8 10 0
参考程序: #include <stdio.h> #include <string.h> #define MAX_LEN 200 int an1[MAX_LEN+10]; int an2[MAX_LEN+10]; char szLine1[MAX_LEN+10]; char szLine2[MAX_LEN+10]; int main() { scanf("%s", szLine1); scanf("%s", szLine2); int i, j; //库函数memset将地址an1开始的sizeof(an1)字节内容置成0 //sizeof(an1)的值就是an1的长度 //memset函数在string.h中声明 memset( an1, 0, sizeof(an1)); memset( an2, 0, sizeof(an2)); //下面将szLine1中存储的字符串形式的整数转换到an1中去, //an1[0]对应于个位 int nLen1 = strlen( szLine1); j = 0;
接下来算4×5。此处4×5的结果代表20个10,因此要 aResult[1]+=20,变为:
再下来算4×3。此处4×3的结果代表12个100,因此要 aResult[2]+= 12,变为:
最后算 4×8。此处4×8的结果代表 32个1000,因此要 aResult[3]+= 32,变为:
乘法过程完毕。接下来从 aResult[0]开始向高位逐位处理进位问题。aResult[0]留下5, 把4加到aResult[1]上,aResult[1]变为51后,应留下1,把5加到aResult[2]上……最终 使得aResult里的每个元素都是1位数,结果就算出来了:
解题思路
基本的思想是反复做减法,看看从被除数里最多能减去多少个除数, 商就是多少。一个一个减显然太慢,如何减得更快一些呢?以7546 除以23为例来看一下:开始商为0。先减去23的100倍,就是2300, 发现够减3次,余下646。于是商的值就增加300。然后用646减去 230,发现够减2次,余下186,于是商的值增加20。最后用186减 去23,够减8次,因此最终商就是328。
2 大整数乘法
问题描述 求两个不超过200位的非负整数的积。
输入数据 有两行,每行是一个不超过200位的非负整数,没有多余的前导0。 输出要求 一行,即相乘后的结果。结果里不能有多余的前导0,即如果结果 是342,那么就不能输出为0342。 输入样例 12345678900 98765432100 输出样例 Output Sample: 1219326311126352690000
相关文档
最新文档