任务
请你实现一个程序,输出 2 的 1000 次方的结果是多少。
思考
- C 语言中给我们提供的 int 类型,肯定是无法完成这个任务的,因为它表示不了这么大的数字。
- 用 long long 类型来进行解决,但long long 是 64 位整型,也就是占 64 个 2 进制位,它顶多能表示 2 的 64 次方减 1 的结果,相对于 2 的 1000 次方来说,小太多了。
- 用double类型进行解决,但存在一个严重的问题,就是 double 是有精度损失的。
(double 的表示精度,一般来说是有效数字 15 位,就是一个数字,由左向右,从第一个不为零的数字起,向后 15 位都是准确的。因此 double 类型实际上也没有办法,准确表示 2 的 1000 次方的计算结果。)
那该怎么办呢?
编码解决
大整数表示法
这种表示法中,使用数组的第 0 位存储数字的位数,因为 3526 有 4 位,所以数组的第 0 位就设置成了 4 这个值。接下来,数组从第 1 位到第 4 位记录的就是原数字 3526。
注意:这个数字是好像是倒着放置的,数字的最高位,也放在数组的最高位中。
如何计算大整数加法
计算 445 + 9667:
首先我们用大整数表示法,分别表示 445 和 9667 这两个数字;然后以位数最长的那个大整数,作为计算结果大整数的基础位数,445 和 9667 按位相加,得到一个 4 位的结果大整数,4 位分别是,9、10、10、12;最后我们再依次处理进位,就得到了底下那一行的结果:10112。
1 | // 定义一个交换两个变量值的宏 swap |
实现
要计算 2 的 1000 次方的结果,就是要计算 1000 次乘法,最终的结果由于数值太大,我们肯定要使用大整数表示法了,所以要想理解这个计算过程,我们还是得回到大整数表示法本身,所对应的数学模型理解上。
如上图所示,我们把大整数表示法中,每一个数字所对应的位权写出来,那么数组中所存储 3、5、2、6 的大整数信息,其实等价于下面的那一行数学公式,即 3∗10^3+5∗10^2+2∗10^1+6∗10^0。
我们对 3526 这个大整数乘以 2,其实等价于对下面那个数学式子乘以 2,就可以得到如下结果:
对某个大整数乘 2 的操作,其实,可以看成是对这个大整数的每一位分别乘以 2 的操作,然后再仿照大整数加法的过程,依次处理进位即可。
1 |
|
小结
- 在大整数的表示法中,数字是从右到左,倒着存放在数组中的。
- 大整数的表示法,体现的是数据结构对于程序设计的作用。
- 大整数的加法和乘法过程,体现的则是算法对于程序设计的作用。
- 算法的底层是数学。
- 如果是计算流程不合理,我们需要改进算法;如果是数据表示受限,我们需要求助于数据结构。