代码没有什么神奇之处,就是模拟手算竖式除法的过程
但需要说明的是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;
}