巨大数的原理解释和初始化获取

引入巨大数的原因:
因为在C语言中,例如int类型,因为int型常量的本质是4字节(32位)补码,当数值最大为2^31 - 1,即只能表示-2147483648 ~ 2147483647,而对于更大的数例如几十位几百位的数,则无法用系统原有类型存储了,此时就需要引入巨大数概念。

巨大数的存储思考:
对于巨大数的存储,很容易能想到用字符串存储,将每个字符换成数字进行计算,但这种方法一位一位运算过于繁琐,效率太低。
这时可以引入万进制的概念。

万进制:
万进制即类似十进制,上限为9,万进制上限为9999,9999再加一则进位,理想在C语言中存储应该表示为1,0。
实际这种想法可以扩展到各种进制,但因为乘法进位位数特别多,当采用十万进制时,五位×五位数据可能超过21亿,超过了int能存储的最大数,所以用十万进制就不能进行计算了。
在保证计算便利和数据合理的前提下,万进制是最适合的。

巨大数存储:
通过思考后,因为巨大数是通过字符串取4位转成数字存储的,所以巨大数数据应该用一个int数组存放,额外还有符号,为了计算方便还需要记录有效位数。

typedef struct HUGE{
	boolean sign;
	int *data;
	int size;
}HUGE;

分别存储正负,数据,数据有效位数

巨大数的初始化:
明确了用结构体存储后,就该进行巨大数的获取(巨大数初始化)的思考了。
这次巨大数的获取是从文件获取的,所以包含一系列文件操作。
首先因为数据用数组的形式存储,数组以动态申请,申请时的位数需要提前知道。
对于文件数据位数获取,在之前的文件操作中有写到,就一笔带过就行。

boolean getsize(FILE *fp, int *size) {
	fseek(fp, 0, SEEK_END);
	(*size) = ftell(fp);
	fseek(fp, 0, SEEK_SET);
}

得到size后,因为可能有一位是符号,则需要对第一个字符判断,若为符号,size需减一并且给sign赋值

if ('-' == ch) {
		sign = 1;
		size--;
	} else {
		sign = 0;
	}

在获取到size后,数组中一个元素用于存4位巨大数,那么数组总元素个数是否是size / 4呢?
若巨大数为4的整数倍位,直接除4即可,但当位数不足4(%4结果不足4),直接除4会造成数组存储空间不足。
获取元素总数计算方法:count = (size + 3) / 4
至此,巨大数结构体的初始化所需要的基础数据就获取完成了,接下来是巨大数数据的获取。

对于巨大数数据的获取,因为数据在文件中是从高位存到低位,数据位数不一定是4的整数倍,这会造成数据最高位可能不足4位,所以对于最初的一组元素需要特别获取。

	head = size % 4;
	for (i = 0; i < head; i++) {
		if (1 == sign) {
			tmp[i] = fgetc(fp);
		} else {
			tmp[i] = ch;
			ch = fgetc(fp);
		}
	}
	if (0 != head){
		huge->data[figure++] = atoi(tmp);
	}

首先得到最高位数据是否够4位,若够则不用特别获取。
因为我们是从文件中获取数据,在符号的判断时做过一次ch = fgetc()所以要注意第一位不要漏掉,有可能在符号判断已经获取了。
对于字符串转换成int数都采用atoi(),十分方便。
剩余数据获取:

if (1 == sign) {
		i = head + 1;
	} else {
		i = head;
	}
	if (1 == sign) {
		ch = fgetc(fp);
	}
	while (i < size) {
		for (j = 0; j < 4; j++) {
			tmp[j] = ch;
			ch = fgetc(fp);
			i++;
		}
		huge->data[figure++] = atoi(tmp);
	}

注:若为负数,ch一直是负号没有变,所以对负数剩余数据的获取需要额外进行一个赋值操作。
至此巨大数初始化及其获取就完成了,完整函数如下:

boolean initHuge(HUGE *huge, int size, FILE *fp) {
	int count;
	int head;
	char tmp[4] = {0};
	int figure = 0;
	int i;
	int j;
	char ch;
	boolean sign;

	ch = fgetc(fp);
	if ('-' == ch) {
		sign = 1;
		size--;
	} else {
		sign = 0;
	}
	count = (size + 3) / 4;
	head = size % 4;

	huge->sign = sign;
	huge->size = size;
	huge->data = (int *) calloc(sizeof(int), count);

	if (NULL == huge->data) {
		return FALSE;
	}

	for (i = 0; i < head; i++) {
		if (1 == sign) {
			tmp[i] = fgetc(fp);
		} else {
			tmp[i] = ch;
			ch = fgetc(fp);
		}
	}
	if (0 != head){
		huge->data[figure++] = atoi(tmp);
	}
	if (1 == sign) {
		i = head + 1;
	} else {
		i = head;
	}
	if (1 == sign) {
		ch = fgetc(fp);
	}
	while (i < size) {
		for (j = 0; j < 4; j++) {
			tmp[j] = ch;
			ch = fgetc(fp);
			i++;
		}
		huge->data[figure++] = atoi(tmp);
	}

	return TRUE;
}

有了获取就可以完成巨大数的显示和销毁函数了:

boolean destoryData(HUGE huge) {
	free(huge.data);
}
void showHuge(HUGE huge) {
	int count;
	int i = 0;
	count = (huge.size + 3) / 4;
	if (1 == huge.sign && 0 != huge.data[0]) {
		printf("-");
	}
	printf("%d", huge.data[0]);

	for (i = 1; i < count; i++) {
		printf("%04d", huge.data[i]);
	}
	printf("\n");
}

在巨大数输出函数中,除前四位外,其他数据空位由0填补,而前四位不需补零输出。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

魔幻音

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值