大数运算

学校大作业要求实现任意大数(可带小数部分)的加减乘除,如果有小数则需要保留10位小数,我采用了vector容器把每一位的数字的储存下来,再通过如同小学竖式计算来实现。那么实际上实现难度不高,唯一难度就是大数除法的实现。而通过对齐除数与被除数,逐位多次相减,则可得出对应位的商。保留10位小数,那么求商就要求到第11位,则被除数后要接上11减去被除数小数长度加上除数小数长度个0,求出结果后再四舍五入即可。

更新:老师不允许用stl,还只能用链表,只好手写一个跟list差不多的类出来,也改进了下代码。

除法运算实现代码

vector<short> divide(vector<short>number1, vector<short>number2, short decimal_length1, short decimal_length2, short decimal_length) {
	vector<short> number;
	number.reserve(60);
	while (!number2[0]) number2.erase(number2.begin());
	short extra_zero = decimal_length - decimal_length1 + decimal_length2;
	short former_number2_size = number2.size();
	for (short i = 0;i < extra_zero;i++)
		number1.insert(number1.end(), 0);
	while (number2.size() < number1.size())
		number2.insert(number2.end(), 0);
	while (number2.size() >= former_number2_size) {
		short digit_result = 0;
		short former_number1_size = number1.size();
		while (1) {
			if (number1.size() == number2.size()) {
				short i = 0;
				for (;i < number1.size() - 1 && number1[i] == number2[i];i++);
				if (number1[i] - number2[i] < 0)
					break;
			}
			if (number1.size() < number2.size())
				break;
			number1 = subtract_for_divide(number1, number2);
			carry(number1);
			digit_result++;
		}
		number.push_back(digit_result);
		number2.pop_back();
	}
	return number;
}

void carry_for_mutiple_and_divide(vector<short>& number, short& decimal_length) {
	for (short j = number.size() - 1;j >= 0;j--) {
		if (number[j] >= 10) {
			if (!j) {
				number.insert(number.begin(), number[j] / 10);
				number[1] %= 10;
				j++;
			}
			else {
				number[j - 1] += number[j] / 10;
				number[j] %= 10;
			}
		}
		else if (number[j] < 0) {
			number[j] += 10;
			number[j - 1]--;
		}
	}
	while (!number[0] && number.size() > 0 && number.size() - decimal_length > 1)
		number.erase(number.begin());
	while (decimal_length > 0 && *(number.end() - 1) == 0) {
		number.pop_back();
		decimal_length--;
	}
}
//双向链表版:
My_List divide(My_List number1, My_List number2, short decimal_length1, short decimal_length2) {
	My_List number;
	while (!number2.head->val) number2.pop_head();
	short extra_zero = 11 - decimal_length1 + decimal_length2;
	short former_number2_size = number2.size;
	for (short i = 0;i < extra_zero;i++)
		number1.push_back(0);
	while (number2.size < number1.size)
		number2.push_back(0);
	while (number2.size >= former_number2_size) {
		short digit_result = 0;
		short former_number1_size = number1.size;
		while (1) {
			if (number1.size < number2.size)
				break;
			number1 = subtract(number1, number2);
			carry(number1);
			bool positive = 1;
			for (node* p = number1.head;p;p = p->next)
				if (p->val < 0) {
					positive = 0;
					break;
				}
			if (positive) digit_result++;
			else {
				number1 = sum(number1, number2);
				break;
			}
		}
		number.push_back(digit_result);
		number2.pop_back();
	}
	return number;
}

void carry_for_md(My_List& number, short& decimal_length) {
	for (node* p = number.end;p;p = p->pre) {
		if (p->val >= 10) {
			if (p == number.head)
				number.push_head(p->val / 10);
			else p->pre->val += p->val / 10;
			p->val %= 10;
		}
	}
	while (!number.head->val && number.size > 0 && number.size - decimal_length > 1)
		number.pop_head();
	while (number.end && decimal_length > 0 && !number.end->val) {
		number.pop_back();
		decimal_length--;
	}
	if (decimal_length > 10) {
		node* p = number.head;
		for (short i = 0;i < number.size - decimal_length + 10;i++)
			p = p->next;
		if (p->val >= 5)
			p->pre->val++;
		if (p->pre->val >= 10) {
			p->pre->val -= 10;
			p->pre->val++;
		}
	}
}

大数运算实现代码

Source

创造的vector数组都使用了reserve,虽然会占用稍多的内存,但可以减少扩充数组(需要将整个vector数组块复制到另一块更大的内存)的次数,从而提高运行速度。

更新:把用双向链表的版本也放进去了,改进了逻辑,感觉代码也没这么乱了,虽然还是接近500行,但是如果直接用stl里的list能删掉差不多一百行,在oj上能跑0s。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值