巨大数的四则运算

  • 目的

巨大数实现的意义在于,当需要计算的数据,超出计算机可表示范围,那么按照平常的计算方法便会无能为力。这时,便需要一种可以解决更大位数计算的方法,也就是巨大数四则运算所存在的意义。而且我们的巨大数还可以为小数,因此起到增加计算精度的作用,在一些需要对数据进行精确计算的科研实验中,便起到巨大的作用。以int为例,当超过-217483648~2147483647范围数字计算机就不能正常表示。

  • 核心技术

  1. 万进制存储

用那种方式存储?这其实也是很值得深思的问题。

字符数组形式存储:这种方式其实在数据的录入时是很简单便利的,但当我们做到加法时,就发现了它的弊端。进行计算时,由于数组中存的是字符形式的,所以在计算时,需要对ASCII码进行转换,才能计算。这样的话便会增加很大的复杂度。而且还有后面的乘法牵扯复杂进位问题,所以这种方式显然是不合适的。

char类型或double类型:这种方式虽说在录入数据时可能复杂一点,但之后的加法和减法运算可以减轻很大的负担。不过呢,加减法虽说还可以实现,但最终的乘法会导致数据逸出。所以这种方式也不太合理。

万进制存储:其实万进制存储也就是用int类型的数组,四位一存。这种方式在理解上其实和我们正常存储的十进制道理是无异的。而我们采取万进制存储的原因是因为,首先10000为10的4次方,这样的话我们直接在一个位上存巨大数的四位,方便录入和计算。其次呢,为什么不是10,100,或者10000等等呢?因为万进制一个位存储的最大9999,在做乘法计算时即使9999乘以9999,依然可以暂时放在这个位上,最后在统一处理。避免了数据的逸出。

巨大数的四则运算_第1张图片

 

     2. 微易码补码

微易码补码是教主(也就是我们老师)多年编程经验总结而成,相当凶悍。

微易码补码的思想,其原理类似于反码和补码,其目的就是为了用加法实现减法。补码的原理是正数补码等于本身,负数则符号位不变,按位取反,末位加一。而至于我们的微易码补码,对于正数也是其本身,负数则是每一位与9取差。其实这里只是补码的原码阶段,可以先暂时理解为原码。

巨大数的四则运算_第2张图片

其实上面的微易码原码在原理上是正确的,但在实际应用时,仅仅只能处理无进位的情况,因此我们需要在前面补一位,这些在后边的具体运算中给大家具体阐述。

  • 巨大数的结构体

typedef struct HUGE{
	int *huge;		//存储巨大数的有效数字
	SIGN sign;		//存储巨大数的符号位
	int length;		//存储巨大数的长度
	int order;		//由于巨大数的阶数(主要为了处理小数)
}HUGE;

这里采用的结构体,每一个都是精心考虑过得,并且也尝试过其他的结构体,暂时这种还是比较合适的,前三个不用都说,至于第四个成员,order主要为了处理小数。因为小数的处理其实是同整数一样,只不过对最终的运算结果变化大小就可以了,也就是通过挪动小数点来实现。

  • 四则运算

注意:由于四则运算对于小数,其实是在整数基础上进行的。因此我们先不要考虑小数的问题。由于加减法的实现是一层一层嵌套的,所以以下的标题和讲解,

  1. 整数的加法和减法

这里为什么把加法和减法放到一起呢,因为我们有微易码补码。他就是把减法用加法来实现,因此不就是,一种情况了。

手工过程:

巨大数的四则运算_第3张图片

上述的手工过程类似于加法,但切不可像加法那样直接加,冒号前的符号位的得到每一步也是不同的。

其实,上述的计算过程,如果你细心考虑,可以发现一个很大的漏洞。我们可以发现,按照我们的办法,计算的结果的位数永远小于等于计算数的位数,想到这,是不是发现跟我们正常的计算所违背。9999+8888就是大于9999,这时上面的方法似乎直接崩塌。其实针对这一点,我们还是有一个神操作的,那就是在计算数前面补一位0,这里的补一位0可不简单。因为是万进制,所以整数是补一个万进制0.可能这么说你还不是很明白,还是来看看手工过程吧。

巨大数的四则运算_第4张图片

有了上面的手工过程,这时再来编程,就方便多了。

    2.小数的加减法

有了上面整数的加减法,小数的加减法,可以看成整数加减法,之后再进行移位小数点来改变结果的大小。我们可以将小数点挪到数据的最右端,改成这样的形式,

这里的a就是我们结构体里的huge所存的有效数字,而b为order便是阶数,因此b基本为非正数。这样的话,我们只需对有效数字进行相加,而结果的阶数便是阶数较大者的阶数。

我在具体的实现时呢,其实是牺牲了一点空间,从新申请两段空间,长度为取两个数整数部分较长者的整数长度加上小数部分较长者的小数部分长度,也就是给出一个最大长度数组,用来存有效数字,以保证加法时的对齐小数点。其实按照阶数相等再加的话,可以节省点空间,这里暂时不纠结了,在小数乘法时,我便是按照阶数相等的方法运算的。

巨大数的四则运算_第5张图片

 

3.乘法运算

整数相乘其实不难,因此这里不予讨论。而小数的乘法,其实也是类似整数的乘法。

巨大数的四则运算_第6张图片

  • 总结

巨大数的四则运算,在实现的过程中,艰难程度比之前的贪吃蛇要复杂一点。不过,因为有比较牛逼的微易码补码给予技术支持,还是降低了很大的难度。而这些微易码补码的使用,就是来源于手工过程的强悍。整个项目下来,真心打心里认识到了手工过程的重要。与其直接敲代码两天,不如花上几个小时,分析分析手工过程,再来编程可谓得心应手了。

 

完整版代码已发至GitHub上

https://github.com/kennDJ/hugeNum

 

 

你可能感兴趣的:(数据结构与算法)