朴素大数除法(竖式除法)的C++实现

代码没有什么神奇之处,就是模拟手算竖式除法的过程
但需要说明的是div3函数的实现是非常低效的,只用于测试div4函数代码的正确性,请不要真正把它用于计算大数除法
div4是效率较高的朴素大数除法的实现,真正模拟了手算竖式除法,其中调用的trialQuoting函数一共提供了三种试商算法的实现,分别是减法试商,二分区间试商和预处理试商,三种方法各有优点和不足没有哪一种方法是最好的
C++代码:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

string charToStr(char be_converted)   
{
	string temp("a");
	if (be_converted != '\0')
		temp[0] = be_converted;
	else
		temp[0] = '0';
	return temp;
}

enum class prefix { left, right, non };
pair<string::size_type, pair<prefix, string::size_type>> alignment(string& left, string& right)
{
	prefix has_prefix_zero;
	string::size_type prefix_zero_length;
	if (left.size() < right.size())
	{
		has_prefix_zero = prefix::left;
		prefix_zero_length = right.size() - left.size();
		left.append(prefix_zero_length, '0');
	}
	else if (left.size() > right.size())
	{
		has_prefix_zero = prefix::right;
		prefix_zero_length = left.size() - right.size();
		right.append(prefix_zero_length, '0');
	}
	else
	{
		has_prefix_zero = prefix::non;

	}
	return { left.size(), {has_prefix_zero, prefix_zero_length} };
}

void deletePrefixZero(const pair<prefix, string::size_type>& has_prefix_zero, string& left, string& right)
{
	if (has_prefix_zero.first == prefix::left)
	{
		left.erase(left.size() - has_prefix_zero.second);
	}
	else if (has_prefix_zero.first == prefix::right)
	{
		right.erase(right.size() - has_prefix_zero.second);
	}
}

string add(string& left, string& right)  //输入倒置,输出倒置
{
	auto r = alignment(left, right);
	string::size_type size = r.first;
	int carry = 0;
	string result;
	for (string::size_type i = 0; i < size; ++i)
	{
		int temp = left[i] - 48 + right[i] - 48 + carry;
		carry = temp / 10;
		result += to_string(temp % 10);
	}
	if (carry != 0)
	{
		result += to_string(carry);
	}
	deletePrefixZero(r.second, left, right);
	return result;

}

string multiply(const string& left, const string& right)  //输入倒置,输出倒置
{
	if (left == "0" || right == "0")
		return "0";
	vector<vector<int>> add_matrix(right.size(), vector<int>(left.size() + 1, 0));
	{
		int carry = 0;
		for (string::size_type i = 0; i < right.size(); ++i)
		{
			carry = 0;
			string::size_type j = 0;
			for (; j < left.size(); ++j)
			{
				int temp = (left[j] - 48) * (right[i] - 48) + carry;
				add_matrix[i][j] = temp % 10;
				carry = temp / 10;
			}
			add_matrix[i][j] = carry;
		}
	}

	string result;
	string carry = "0";
	for (size_t t = 1; t <= left.size() + right.size(); ++t)
	{
		size_t start_group = 0;
		long long start_index = left.size();
		if (t > left.size() + 1)
		{
			start_group = t - left.size() - 1;
		}
		else
		{
			start_index = t - 1;
		}

		string temp = "0";
		while (start_group < right.size() && start_index >= 0)
		{
			string str_form = to_string(add_matrix[start_group][start_index]);
			if (str_form != "0")
				temp = add(temp, str_form);
			++start_group;
			--start_index;
		}

		if (carry != "0")
			temp = add(temp, carry);
		result += charToStr(temp[0]);
		carry = temp.substr(1, temp.size() - 1);
		if (carry == "")
			carry = "0";
	}

	if (result[result.size() - 1] == '0')
	{
		return result.substr(0, result.size() - 1);
	}
	else
	{
		return result;
	}
}

string substract(string& left, string& right)  //返回left-right,输入倒置,输出倒置
{
	bool borrow = false;
	auto r = alignment(left, right);
	string::size_type size = r.first;
	string result;
	long long i = size - 1;
	for (; i >= 0; --i)
	{
		if (left[i] > right[i])
		{
			for (string::size_type i = 0; i < size; ++i)
			{
				if (borrow)
				{
					if (left[i] == '0')
					{
						result += charToStr(static_cast<char>(('9' - right[i] + 48)));
					}
					else
					{
						char t = left[i] - 1;
						if (t < right[i])
						{
							result += charToStr(static_cast<char>(t + 10 - right[i] + 48));
						}
						else
						{
							result += charToStr(static_cast<char>(t - right[i] + 48));
							borrow = false;
						}
					}
				}
				else
				{
					if (left[i] == '0')
					{
						if (right[i] == '0')
						{
							result += "0";
						}
						else
						{
							result += charToStr(static_cast<char>(10 - (right[i] - 48) + 48));
							borrow = true;
						}
					}
					else
					{
						if (left[i] < right[i])
						{
							result += charToStr(static_cast<char>(left[i] + 10 - right[i] + 48));
							borrow = true;
						}
						else
						{
							result += charToStr(static_cast<char>(left[i] - right[i] + 48));
						}
					}
				}
			}
			break;
		}
		else if (left[i] < right[i])
		{
			for (string::size_type i = 0; i < size; ++i)
			{
				if (borrow)
				{
					if (right[i] == '0')
					{
						result += charToStr(static_cast<char>(('9' - left[i] + 48)));
					}
					else
					{
						char t = right[i] - 1;
						if (t < left[i])
						{
							result += charToStr(static_cast<char>(t + 10 - left[i] + 48));
						}
						else
						{
							result += charToStr(static_cast<char>(t - left[i] + 48));
							borrow = false;
						}
					}
				}
				else
				{
					if (right[i] == '0')
					{
						if (left[i] == '0')
						{
							result += "0";
						}
						else
						{
							result += charToStr(static_cast<char>(10 - (left[i] - 48) + 48));
							borrow = true;
						}
					}
					else
					{
						if (right[i] < left[i])
						{
							result += charToStr(static_cast<char>(right[i] + 10 - left[i] + 48));
							borrow = true;
						}
						else
						{
							result += charToStr(static_cast<char>(right[i] - left[i] + 48));
						}
					}
				}
			}
			break;
		}
	}

	if (i >= 0)
	{
		long long j = result.size() - 1;
		for (; j >= 0; --j)
		{
			if (result[j] != '0')
			{
				break;
			}
		}
		if (left[i] < right[i])
		{
			result = result.substr(0, j + 1) + "-";
		}
		else
		{
			result = result.substr(0, j + 1);
		}
		deletePrefixZero(r.second, left, right);
		return result;

	}
	else
	{
		return "0";
	}
}

bool isNegative(const string& p)
{
	if (p != "0" && p.back() == '-')
	{
		return true;
	}
	return false;
}

bool compare2(string& left, string& right)
{
	if (left.size() < right.size())
		return true;
	if (left.size() > right.size())
		return false;
	for (string::size_type i = left.size() - 1; ; --i)
	{
		if (left[i] > right[i])
		{
			return false;
		}
		else if (left[i] < right[i])
		{
			return true;
		}
		if (i == 0)
			break;
	}
	return true;
}

void doSubtract(string& r, string& right, string& part)
{
	while (compare2(right, r))
	{
		r = substract(r, right);
		string one("1");
		part = add(part, one);
	}
}

string div3(string& left, string& right, size_t precision)  //返回字符串从左至右高位到低位,输入字符串相反,精度规定小数点后最大位数,输入倒置,输出正置
{
	string part_r(left);
	string part_quotient = "0";
	doSubtract(part_r, right, part_quotient);

	reverse(part_quotient.begin(), part_quotient.end());
	if (part_r == "0" || precision == 0)
	{
		return part_quotient;
	}
	part_quotient += ".";

	size_t count = 0;
	while (true)
	{
		part_r.insert(part_r.begin(), 1, '0');
		string p_q = "0";

		doSubtract(part_r, right, p_q);

		part_quotient += p_q;
		++count;
		if (count == precision || part_r == "0")
		{
			return part_quotient;
		}
	}
}

enum class result { small, big, equal };
result compare3(string& left, string& right)
{
	if (left.size() < right.size())
		return result::small;
	if (left.size() > right.size())
		return result::big;
	for (string::size_type i = left.size() - 1; ; --i)
	{
		if (left[i] > right[i])
		{
			return result::big;
		}
		else if (left[i] < right[i])
		{
			return result::small;
		}
		if (i == 0)
			break;
	}
	return result::equal;
}

int binaryTrialQuoting(string& r, string& divisor)
{
	int left = 0;
	int right = 10;
	while (true)
	{
		int mid = (left + right) / 2;
		string temp = "0";
		if (mid != 0)
			temp = multiply(to_string(mid), divisor);
		result re = compare3(temp, r);
		if (re == result::equal)
		{
			r = "0";
			return mid;
		}
		else if (re == result::small)
		{
			if (right - left == 1)
			{
				if (left != 0)
				{
					r = substract(r, temp);
				}
				return left;
			}
			left = mid;
		}
		else
		{
			right = mid;
		}
	}
}

int binaryTrialQuoting2(string& r, string& divisor, vector<string>& PreCalculation)
{
	int run = 0;
	while (true)
	{
		if (run == 10 || compare3(r, PreCalculation[run]) == result::small)
		{
			r = substract(r, PreCalculation[run - 1]);
			return run - 1;
		}
		++run;
	}
}

enum class trialQuotingOP { start, binary, preCal };
string trialQuoting(string& r, string& divisor, trialQuotingOP op_class, vector<string>& PreCalculation)
{
	if (op_class == trialQuotingOP::start)
	{
		string q = "0";
		doSubtract(r, divisor, q);
		return q;
	}
	else if (op_class == trialQuotingOP::binary)
	{
		return to_string(binaryTrialQuoting(r, divisor));
	}
	else
	{
		return to_string(binaryTrialQuoting2(r, divisor, PreCalculation));
	}
}

string div4(string& left, string& right, size_t precision, trialQuotingOP op_class) //left正置,right倒置,结果正置
{
	vector<string> PreCalculation(10);
	PreCalculation[0] = "0";
	for (int i = 1; i <= 9; ++i)
	{
		PreCalculation[i] = multiply(to_string(i), right);
	}

	string r;
	string::size_type scan;
	if (left.size() <= right.size())
	{
		r = left;
		scan = left.size();
		reverse(r.begin(), r.end());
	}
	else
	{
		scan = right.size();
		r = left.substr(0, scan);
		reverse(r.begin(), r.end());
		if (compare2(right, r) == false)
		{
			r.insert(r.begin(), 1, left[scan++]);
		}
	}

	string result;
	bool has_added_point = false;
	int count = 0;
	while (true)
	{
		result.append(trialQuoting(r, right, op_class, PreCalculation));
		if (has_added_point)
			++count;

		if (r == "0" && has_added_point)
		{
			return result;
		}
		else
		{
			if (r != "0")
			{
				if (precision == count)
				{
					if (count != 0 || scan == left.size())
					{
						return result;
					}
				}
			}
			else
			{
				if (scan == left.size())
					return result;
			}
		}

		if (scan == left.size())
		{
			if (has_added_point == false)
			{
				result.append(1, '.');
				has_added_point = true;
			}
			if (r != "0")
				r.insert(r.begin(), 1, '0');
		}
		else
		{
			if (r != "0")
			{
				r.insert(r.begin(), 1, left[scan]);
			}
			else
			{
				if (left[scan] != '0')
				{
					r = string(1, left[scan]);
				}
			}
			++scan;
		}
	}
}

int main()
{
	string left = "123";
	string right = "456";
	string left2 = left;
	string div_r = div3(left, right, 10);
	cout << "div3:";
	cout << div_r << endl;

	string div_r2 = div4(left2, right, 10, trialQuotingOP::preCal);
	cout << "div4:";
	cout << div_r2 << endl;

	for (int i = 9000; i <= 10000; ++i)
	{
		for (int j = 90; j <= 100; ++j)
		{
			string left = to_string(i);
			string right = to_string(j);
			string left2 = left;
			reverse(left.begin(), left.end());
			reverse(right.begin(), right.end());

			cout << i << "/" << j << endl;
			string div_r = div3(left, right, 10);
			cout << "div3:";
			cout << div_r << endl;

			string div_r2 = div4(left2, right, 10, trialQuotingOP::preCal);
			cout << "div4:";
			cout << div_r2 << endl;
			if (div_r == div_r2)
			{
				cout << "运算结果正确" << endl;
			}
			else
			{
				cout << "ERROR:运算结果错误!" << endl;
				exit(-1);
			}
			cout << endl;
		}
	}
	return 0;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值