乘法的运算受限于数据类型的表示范围,比如int类型的乘法,32位的无符号整形
unsigned int 最大可表示0xffffffff。
有时问题会要求我们进行较大的数值的计算,我们除了使用表示范围较大的数据类型(事实上,这仍不可靠)外,还可以选择高精度的乘法模拟。
例如,有这么一个问题:输入一个不超过1000的正整数n,输出n!的精确结果。
显然int类型来表示这个结果会产生溢出。
下面简单讲讲高精度乘法的一般过程:高精度乘法要求我们开一个数组(假设用f[maxn]表示),用其中的每一位代表运算结果的每一位。因此,我们要对问题要求的计算结果进行分析,估算大致位数,来决定maxn的大小,就这个例子看来,最大的输出结果1000!约有2600位,故开辟一个3000维的数组足够保存结果。
进行乘法模拟,不失一般性,取一次乘法过程来模拟,被乘数已经存放在f数组中,乘数是x,算法伪代码如下
1 For j=1 to maxn 2 int s ← f[j]*被乘数 + 进位; 3 f[j] ← s % 10; //求解每一位的值 4 进位 ← s / 10; //求解余数
模拟的算法相当简单:就是对被乘数的每一位,都乘以乘数,并加上进位(初始化为0),并更新f数组的值。
每一遍计算完成后,f数组中保存的就是结果的每一位的值,当然,这里还可以压缩下外循环,因为每次f中保存的值的有效位数是确定的,就可以根据有效位数来决定外循环次数,不一定要每次都执行maxn遍。
模拟方法讲完了,接下来就来解决一下上面的问题,代码用C++实现:
1 #include<iostream> 2 #include<cstring> 3 #define maxn 3000 //数组开足够大,这里3000即可 4 using namespace std; 5 int f[maxn]; 6 int main(){ 7 int n; 8 cin >> n; //输出n! 9 memset(f, 0, sizeof(f)); //初始化为全0 10 f[1] = 1; //f数组保存被乘数,即每一次的运算结果 11 for(int i =2; i <= n; ++i){ //计算n-1次 12 int c = 0; //进位初始化 13 for(int j = 1; j <= maxn; ++j){ //遍历每一位 14 int s = f[j] * i + c; 15 f[j] = s % 10; 16 c = s / 10; 17 } 18 } 19 int beg; 20 for(beg = maxn; beg >= 1; --beg) //忽略前导的0 21 if(f[beg]) break; 22 for(int i = beg; i >= 1; --i) 23 cout<<f[i]; 24 return 0; 25 }
后记:博客园的第一篇随笔,随便水一下2333