大数是算法语言中的数据类型无法表示的数,其位数超过最大数据类型所能表示的范围,所以,在处理大数问题时首先要考虑的是怎样存储大数,然后是在这种存储方式下其处理的实现方法。
一般情况下大数的存储是采用字符数组来存储,即将大数当作一个字符串来存储,而对其处理是按其处理规则在数组中模拟实现。
五 大数幂次。
问题来源: 《c程序设计竞赛实训教程》
问题描述:
计算国债对于计算机来说是一件很繁重的事情,该问题涉及到的精度很高。现需要你编写一个程序用来计算R的n次方。 这里R是一个实数(0.0<R<99.999),而n是一个整数.
问题分析:
计算结果的位数很长,还是涉及到大数的处理,不能用普通类型数表示,只能用数组表示,类似于大数的做法,利用数组来模拟手算过程。为了计算方便,数组中将小数点去掉,记住其位置,然后只计算整数的幂次,最后将小数点在结果中的位置计算出来,放在结果中即可。
其实本质上也是大数乘法的一部分。只是这里涉及了小数点的处理。
思想差不多,也就没自己去写。 下面的代码来自书中的实例源码。
- #include<stdio.h>
- #include<string.h>
- #define N 200
- //函数mult功能: 实现p1中长度为len1的大数和p2中长度为len2的大数相乘,
- //结果保存在p2中,同时返回结果的位长len2
- void Mult( int *p1, int *p2, int len1, int *len2 )
- {
- int i, j, k, d, ts[N];
- for ( i=0; i<N; i++ )
- ts[i] = 0;
- for ( i=0; i<len1; i++ )
- for ( j=0; j<*len2; j++ )
- ts[i+j] += p1[i] * p2[j]; //大数乘法
- k = len1 + (*len2); //结果可能最大位长
- while ( k>0 && ts[k]==0 )
- k--;
- k++;
- for ( i=0,d=0; i<k; i++ ) //处理进位
- {
- p2[i] = ( ts[i] + d ) % 10;
- d = ( ts[i] + d ) / 10;
- }
- if ( d>0 ) //最高位进位
- {
- p2[i] = d;
- k++;
- }
- *len2 = k;
- }
- int main()
- {
- char str_a[10], str_b[N+1];
- int i, t, j, k, len_a, len_b, n, pot;
- int a[10], b[N];
- scanf("%d",&t); //读入测试组数
- while ( t-->0 )
- {
- scanf("%s%d", str_a, &n );
- len_a = strlen(str_a);
- k = len_a - 1;
- while ( k>=0 && str_a[k] != '.' ) //找出小数点位置
- k--;
- if ( k<0 ) //小数点后的位数
- pot = 0;
- else
- {
- j = len_a - 1;
- while ( j>0 && str_a[j]=='0' ) //去掉小数点尾部的0
- j--;
- len_a = j + 1;
- str_a[len_a] = '\0';
- pot = len_a -k - 1; //小数点后的位数
- }
- i = len_a - 1;
- k = 0;
- while ( i>=0 )
- {
- if ( str_a[i] != '.' ) //将大数颠倒存入并且去掉小数点
- a[k++] = str_a[i] - '0';
- i--;
- }
- for ( i=0; i<N; i++ )
- b[i] = 0;
- len_a = len_b = k;
- for ( i=0; i<len_a; i++ )
- b[i] = a[i]; //乘数相同
- for ( i=1; i<n; i++ )
- Mult( a, b, len_a, &len_b ); //做n-1次相乘
- k = pot * n; //小数点位置
- n = len_b > k? len_b:k;
- for ( j=0,i=n-1; i>=0; i-- ) //结果转为字符串
- {
- if ( i==k-1 )
- str_b[j++] = '.';
- str_b[j++] = b[i] + '0';
- }
- str_b[j] = '\0';
- printf("%s\n",str_b); //输出结果
- }
- return 0;
- }