- C++
高精度除法
- 2025-5-16 10:09:57 @
C++ 高精度除法教程(0基础通俗易懂)
📚 什么是高精度除法?
在C++中,像 int
、long long
这样的整型变量都有表示范围的限制。当我们需要处理非常大的整数(比如几万位的大数)时,普通的运算就会溢出,无法正确计算。
所以我们就需要使用字符串或数组来模拟大数运算。这就是所谓的 “高精度算法”。
今天我们要学习的是:高精度除法,也就是如何用C++手动实现两个大整数之间的除法操作。
🧠 基本思路:模拟手算过程
我们小时候学过怎么做竖式除法:
123
_______
45 ) 5535
-45
----
103
- 90
----
135
-135
----
0
我们可以把这个过程一步步地用代码模拟出来:
- 每次从被除数高位开始取一位(或几位)
- 看是否大于等于除数
- 尝试商是多少,并做减法
- 把余数带入下一轮继续
但为了简化逻辑,我们采用一个更高效的方法:二分查找 + 高精度比较 + 减法
📌 总体步骤概览
我们会把整个除法分为以下几步:
- 输入两个大整数(作为字符串)
- 判断符号,处理负数
- 实现几个辅助函数:
- 大数比较(compare)
- 大数减法(subtract)
- 大数乘法(multiplySingleDigit,用于试商)
- 主要逻辑:模拟每一位的试商 + 减法操作
- 输出结果(商和余数)
💡 核心思想:试商 + 逐位处理
我们不按小学竖式那样做,而是这样处理:
- 对于当前处理的被除数前缀,尝试找出最大可以减去多少个除数(即这个位置的商)
- 使用二分查找快速找到合适的商(0~9)
- 然后做减法,更新当前余数
- 继续处理下一位
🛠️ 数据结构选择
我们依然使用字符串来存储大数,处理时也可以临时转成 vector<int>
来方便操作。
例如:
string num = "1234567890";
vector<int> v;
for (char c : num)
v.push_back(c - '0');
💻 示例代码(完整可运行)
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// 去掉前导零
string removeLeadingZeros(const string& s) {
int i = 0;
while (i < s.size() - 1 && s[i] == '0') i++;
return s.substr(i);
}
// 判断 a >= b ?
bool compare(const string& a, const string& b) {
if (a.size() != b.size())
return a.size() > b.size();
return a >= b;
}
// 高精度减法(a >= b)
string subtract(const string& aStr, const string& bStr) {
string a = removeLeadingZeros(aStr);
string b = removeLeadingZeros(bStr);
vector<int> A, B;
for (char c : a) A.push_back(c - '0');
for (char c : b) B.push_back(c - '0');
reverse(A.begin(), A.end());
reverse(B.begin(), B.end());
vector<int> res;
int borrow = 0;
for (int i = 0; i < A.size(); i++) {
int ai = A[i];
int bi = (i < B.size()) ? B[i] : 0;
int diff = ai - bi - borrow;
if (diff < 0) {
diff += 10;
borrow = 1;
} else {
borrow = 0;
}
res.push_back(diff);
}
// 去除前导零
while (res.size() > 1 && res.back() == 0)
res.pop_back();
string result;
for (int i = res.size() - 1; i >= 0; i--)
result += to_string(res[i]);
return result;
}
// 单位乘法:num × digit (digit 是 0~9)
string multiplySingleDigit(const string& num, int digit) {
if (digit == 0) return "0";
string res;
int carry = 0;
for (int i = num.size() - 1; i >= 0; i--) {
int val = (num[i] - '0') * digit + carry;
res.push_back('0' + (val % 10));
carry = val / 10;
}
if (carry) res.push_back('0' + carry);
reverse(res.begin(), res.end());
return res;
}
// 高精度除法主函数(返回商)
string divide(const string& dividend, const string& divisor) {
if (divisor == "0") {
cout << "错误:除数不能为0!" << endl;
return "";
}
// 处理符号
bool isNegative = (dividend[0] == '-') ^ (divisor[0] == '-');
string a = removeLeadingZeros(dividend[0] == '-' ? dividend.substr(1) : dividend);
string b = removeLeadingZeros(divisor[0] == '-' ? divisor.substr(1) : divisor);
if (a == "0") return "0";
if (compare(b, a)) return "0";
string current = ""; // 当前被除数部分
string quotient; // 商
for (char digit : a) {
current.push_back(digit); // 添加一位到当前被除数
current = removeLeadingZeros(current);
// 用二分查找找最大的商 digit
int low = 0, high = 9;
int best = 0;
while (low <= high) {
int mid = (low + high) / 2;
string product = multiplySingleDigit(b, mid);
if (compare(current, product)) {
best = mid;
low = mid + 1;
} else {
high = mid - 1;
}
}
quotient.push_back('0' + best);
current = subtract(current, multiplySingleDigit(b, best));
}
if (isNegative && quotient != "0")
quotient = "-" + quotient;
return quotient;
}
int main() {
string a, b;
cout << "请输入被除数:";
cin >> a;
cout << "请输入除数:";
cin >> b;
string q = divide(a, b);
if (q != "") {
cout << "商是:" << q << endl;
}
return 0;
}
📖 示例运行
输入:
请输入被除数:5535
请输入除数:45
输出:
商是:123
✅ 总结知识点
内容 | 说明 |
---|---|
使用字符串 | 存储大数,避免溢出 |
辅助函数 | 比较、减法、单位乘法 |
试商方式 | 二分查找快速定位当前位商值 |
支持负数 | 通过符号判断处理正负号 |
去除前导0 | 保证结果简洁 |
🧪 练习建议
你可以试着扩展以下功能:
- 返回余数(修改divide函数返回pair<string, string>)
- 支持浮点除法(添加小数点处理)
- 实现模运算(取余)
- 支持除以0的异常提示优化
🙋♂️ 如何继续学习?
如果你已经掌握高精度除法,可以挑战以下内容:
- 高精度幂运算(如 )
- 高精度阶乘(如 )
- 高精度平方根
- 实现大数四则混合运算器
如果你有具体问题或者希望我扩展哪部分内容,请告诉我!😊
4 条评论
-
admin SU @ 2025-5-19 21:51:46
🧮 C++ 高精度除法教程:逐位试商 + 二分查找优化
0基础也能懂!通俗易懂,附完整代码 + 注释 + 图解风格
🔍 什么是高精度除法?
在C++中,当我们要处理非常大的整数时(比如超过
long long
范围),就不能使用普通的/
和%
运算符了。这时候就需要我们自己模拟竖式除法的过程。本教程介绍一种更高效的实现方式:
逐位试商 + 二分查找优化
这种方法比“暴力从0~9一个个试”快很多,逻辑清晰、适合进阶学习!
🧠 基本思路:模拟竖式除法 + 二分查找商
想象一下小学学的除法过程:
1 2 3 _________ 4 ) 4 9 2 -4 ---- 9 -8 ---- 12 -12 ---- 0
我们可以把这个过程用程序一步一步模拟出来,并且在试商的时候使用二分查找来快速确定当前位的商是多少。
💡 数据结构选择:字符串 + vector
为了方便操作每一位数字,我们将大整数以字符串形式输入,并将其转换为
vector<int>
,按顺序存储每一位。例如:
"12345" → {1, 2, 3, 4, 5}
📦 实现步骤详解
我们将实现以下功能:
- 输入两个大整数 a(被除数)和 b(除数)
- 将 a 拆分成每一位,逐位“带下来”
- 不断尝试当前部分是否大于等于 b
- 使用二分查找找出最大可能的商(q ∈ [0,9])
- 更新余数并继续下一位计算
- 最终输出商和余数
💻 示例代码(完整可运行)
#include <iostream> #include <string> #include <vector> using namespace std; // 去掉前导零 string removeLeadingZeros(const string& s) { int i = 0; while (i < s.size() && s[i] == '0') ++i; if (i >= s.size()) return "0"; return s.substr(i); } // 比较两个 vector<int> 表示的大数:a >= b ? bool compare(const vector<int>& a, const vector<int>& b) { if (a.size() > b.size()) return true; if (a.size() < b.size()) return false; for (int i = 0; i < a.size(); ++i) { if (a[i] > b[i]) return true; if (a[i] < b[i]) return false; } return true; } // 大数减法:a - b,假设 a >= b vector<int> subtract(const vector<int>& a, const vector<int>& b) { vector<int> res; int borrow = 0; for (int i = 0; i < a.size(); ++i) { int ai = a[i]; int bi = (i < b.size()) ? b[i] : 0; int val = ai - bi - borrow; if (val < 0) { val += 10; borrow = 1; } else { borrow = 0; } res.push_back(val); } // 去掉后导零 while (res.size() > 1 && res.back() == 0) res.pop_back(); return res; } // 将字符串转成 vector<int>(顺序存储) vector<int> strToVec(const string& s) { vector<int> res; for (char ch : s) res.push_back(ch - '0'); return res; } // 乘以一个数字(用于二分查找中的 mid * b) vector<int> multiplyByDigit(const vector<int>& num, int digit) { vector<int> res; int carry = 0; for (int i = 0; i < num.size(); ++i) { long long val = num[i] * digit + carry; res.push_back(val % 10); carry = val / 10; } if (carry > 0) res.push_back(carry); return res; } // 主函数:高精度除法(逐位试商 + 二分查找) int main() { string aStr, bStr; cout << "请输入被除数 a(正整数):"; cin >> aStr; cout << "请输入除数 b(正整数,不能为0):"; cin >> bStr; // 处理前导零 aStr = removeLeadingZeros(aStr); bStr = removeLeadingZeros(bStr); if (bStr == "0") { cout << "错误:除数不能为0!" << endl; return 1; } vector<int> a = strToVec(aStr); vector<int> b = strToVec(bStr); vector<int> remainder; // 当前余数 vector<int> quotient; // 商 for (int i = 0; i < a.size(); ++i) { // 把当前位加到余数末尾 remainder.push_back(a[i]); // 去掉前导零 while (remainder.size() > 1 && remainder[0] == 0) remainder.erase(remainder.begin()); // 二分查找合适的商 int low = 0, high = 9; int best_q = 0; while (low <= high) { int mid = (low + high) / 2; vector<int> mid_b = multiplyByDigit(b, mid); // mid * b if (compare(remainder, mid_b)) { best_q = mid; // 可能是答案 low = mid + 1; } else { high = mid - 1; } } // 得到最终商位 best_q vector<int> q_times_b = multiplyByDigit(b, best_q); remainder = subtract(remainder, q_times_b); quotient.push_back(best_q); } // 输出结果 cout << "商 = "; for (int digit : quotient) cout << digit; cout << endl; cout << "余数 = "; for (int digit : remainder) cout << digit; cout << endl; return 0; }
📖 示例运行
输入:
请输入被除数 a(正整数):123456789 请输入除数 b(正整数,不能为0):123
输出:
商 = 1003713 余数 = 78
🧩 关键函数说明
函数名 功能 removeLeadingZeros
去掉字符串前面多余的0 strToVec
将字符串转为顺序存储的 vector compare
判断两个大数是否 a >= b subtract
实现 a - b 的高精度减法 multiplyByDigit
实现大数 × 一位数 main
中逻辑实现逐位试商 + 二分查找优化
🎨 竖式除法图解(伪代码风格)
初始化余数为空 对于每一位 a_i: 把 a_i 加入余数 使用二分查找找到最大可以减去的商 记录该商 更新余数 = 余数 - 商 * b
✅ 总结知识点
内容 说明 使用 vector 存储每一位数字,便于处理进退位 高精度减法 自定义实现两个大数相减 高精度乘法 一位数 × 大数,辅助二分查找 除法模拟 通过逐位试商 + 二分查找模拟竖式除法 支持大数 可以处理任意长度的大整数
🧪 练习建议
你可以试着扩展以下功能:
- [ ] 支持负数输入(带符号判断)
- [ ] 返回值改为结构体,包含商和余数
- [ ] 把结果写入文件保存
- [ ] 加入性能优化(如快速比较、提前终止)
🙋♂️ 如何继续学习?
如果你希望我继续扩展以下内容,请告诉我:
- 如何加入小数部分输出?
- 如何把结果保存为文件?
- 如何用类封装高精度库?
- 如何进一步优化效率?
😊
📌 结语:
通过本教程,你已经掌握了如何用逐位试商 + 二分查找的方式模拟竖式除法的基本方法。这是理解高精度运算的重要一步,也是打牢算法基础的关键环节!需要配套练习题或进阶讲解也可以随时告诉我哦 😊
-
2025-5-19 21:50:37@
🧮 C++ 高精度除法(使用减法模拟)教程
0基础也能懂!通俗易懂,附完整代码 + 注释 + 图解风格
🔍 什么是高精度除法?
在C++中,普通的
int
或long long
类型只能处理有限范围的整数。当我们遇到非常大的整数(比如超过18位)时,就无法用内置类型直接做运算了。这时候,我们需要使用高精度算法来手动模拟大数的加、减、乘、除等操作。
🧠 基本思路:用减法模拟除法
我们都知道:
a ÷ b = 商 q,余数 r
等价于:a - b*q = r所以我们可以用“不断减去 b”的方式来模拟除法的过程:
- 每次减去一个 b,计数器+1
- 直到不能再减为止,此时计数器就是商,剩下的就是余数
虽然这种方法效率不高,但逻辑清晰,适合初学者理解高精度除法的本质!
💡 数据结构选择:字符串 + vector
为了方便处理进位和借位,我们使用
vector<int>
来保存每一位数字,并且按逆序存储(即最低位在前)。例如:
数字 "123" 表示为 {3, 2, 1}
这样从前往后就可以一位一位比较和减法操作。
📦 实现步骤详解
我们将实现以下功能:
- 输入两个大整数 a 和 b(作为字符串)
- 将它们转换成
vector<int>
- 判断 a 是否大于等于 b
- 不断用 a 减去 b,直到不能再减
- 记录减了多少次(商),最后的 a 就是余数
💻 示例代码(完整可运行)
#include <iostream> #include <string> #include <vector> using namespace std; // 去掉前导零 string removeLeadingZeros(string s) { int i = 0; while (i < s.size() - 1 && s[i] == '0') i++; return s.substr(i); } // 字符串转 vector<int>(逆序存储) vector<int> strToVec(const string& s) { vector<int> res; for (auto it = s.rbegin(); it != s.rend(); ++it) res.push_back(*it - '0'); return res; } // 比较两个大数:a >= b ? bool compare(const vector<int>& a, const vector<int>& b) { if (a.size() > b.size()) return true; if (a.size() < b.size()) return false; // 位数相同,从高位开始比较 for (int i = a.size() - 1; i >= 0; --i) { if (a[i] > b[i]) return true; if (a[i] < b[i]) return false; } return true; // 相等 } // 高精度减法:a - b,假设 a >= b vector<int> subtract(const vector<int>& a, const vector<int>& b) { vector<int> res; int borrow = 0; // 借位 for (int i = 0; i < a.size(); ++i) { int ai = a[i]; int bi = (i < b.size()) ? b[i] : 0; int val = ai - bi - borrow; if (val < 0) { val += 10; borrow = 1; } else { borrow = 0; } res.push_back(val); } // 去掉前导零 while (res.size() > 1 && res.back() == 0) res.pop_back(); return res; } // 将 vector<int> 转换为字符串输出 string vecToStr(const vector<int>& v) { string res; for (int i = v.size() - 1; i >= 0; --i) res += to_string(v[i]); return res; } // 主函数:用减法模拟除法 int main() { string aStr, bStr; cout << "请输入被除数 a(正整数):"; cin >> aStr; cout << "请输入除数 b(正整数,不能为0):"; cin >> bStr; // 处理输入 aStr = removeLeadingZeros(aStr); bStr = removeLeadingZeros(bStr); if (bStr == "0") { cout << "错误:除数不能为0!" << endl; return 1; } vector<int> a = strToVec(aStr); vector<int> b = strToVec(bStr); int quotient = 0; // 商 // 用减法模拟除法 while (compare(a, b)) { a = subtract(a, b); // a = a - b quotient++; // 商加一 } // 输出结果 cout << "商 = " << quotient << endl; cout << "余数 = " << vecToStr(a) << endl; return 0; }
📖 示例运行
输入:
请输入被除数 a(正整数):123456789 请输入除数 b(正整数,不能为0):123
输出:
商 = 1003713 余数 = 78
🧩 关键函数说明
函数名 功能 removeLeadingZeros
去掉字符串前面多余的0 strToVec
将字符串转为逆序的 vector compare
比较两个大数是否 a >= b subtract
实现 a - b 的高精度减法 vecToStr
把 vector 转回字符串用于输出
🎨 枚举过程图解(伪代码风格)
a = 123456789 b = 123 商 = 0 while a >= b: a = a - b 商 += 1 最终输出 商 和 余数 a
✅ 总结知识点
内容 说明 使用 vector 存储每一位数字,便于处理进退位 高精度减法 自定义实现两个大数相减 除法模拟 通过重复减法实现除法逻辑 输出方式 逆序打印 vector 中的每一位 支持大数 可以处理任意长度的大整数
🧪 练习建议
你可以试着扩展以下功能:
- [ ] 支持负数输入(带符号判断)
- [ ] 返回值改为结构体,包含商和余数
- [ ] 把结果写入文件保存
- [ ] 加入性能优化(如快速减法)
🙋♂️ 如何继续学习?
如果你希望我继续扩展以下内容,请告诉我:
- 如何优化这个减法模拟除法的性能?
- 如何支持保留小数部分?
- 如何把结果保存为文件?
- 如何用类封装高精度库?
😊
📌 结语:
通过本教程,你已经掌握了如何用减法模拟除法的基本方法。这是理解高精度运算的第一步,也是打牢算法基础的重要环节!需要配套练习题或进阶讲解也可以随时告诉我哦 😊
-
2025-5-19 21:50:21@
🧮 C++ 高精度除法教程:逐位试商法(不用二分)
0基础也能懂!通俗易懂,附完整代码 + 注释 + 图解风格
🔍 什么是高精度除法?
在C++中,当我们要处理非常大的整数时(比如超过
long long
范围),就不能使用普通的/
和%
运算符了。这时候就需要我们自己模拟竖式除法的过程。本教程介绍一种经典的实现方式:
逐位试商法(不使用二分优化)
这种方法逻辑清晰、适合初学者理解,虽然效率不是最高,但能帮助你打下扎实的算法基础!
🧠 基本思路:模拟竖式除法
想象一下小学学的除法过程:
1 2 3 _________ 4 ) 4 9 2 -4 ---- 9 -8 ---- 12 -12 ---- 0
我们可以把这个过程用程序一步一步模拟出来。
💡 数据结构选择:字符串 + vector
为了方便操作每一位数字,我们将大整数以字符串形式输入,并将其转换为
vector<int>
,按顺序存储每一位。例如:
"12345" → {1, 2, 3, 4, 5}
📦 实现步骤详解
我们将实现以下功能:
- 输入两个大整数 a(被除数)和 b(除数)
- 将 a 拆分成每一位,逐位“带下来”
- 不断尝试当前部分是否大于等于 b
- 找出一位合适的商(从0~9依次试)
- 更新余数并继续下一位计算
- 最终输出商和余数
💻 示例代码(完整可运行)
#include <iostream> #include <string> #include <vector> #include<algorithm> using namespace std; // 去掉前导零 string removeLeadingZeros(const string& s) { int i = 0; while (i < s.size() && s[i] == '0') ++i; if (i >= s.size()) return "0"; return s.substr(i); } // 比较两个大数:a >= b ? bool compare(const vector<int>& a, const vector<int>& b) { if (a.size() > b.size()) return true; if (a.size() < b.size()) return false; // 位数相同,从高位开始比较 for (int i = a.size() - 1; i >= 0; --i) { if (a[i] > b[i]) return true; if (a[i] < b[i]) return false; } return true; // 相等 } // 大数减法:a - b,假设 a >= b vector<int> subtract(const vector<int>& a, const vector<int>& b) { vector<int> res; int borrow = 0; for (int i = 0; i < a.size(); ++i) { int ai = a[i]; int bi = (i < b.size()) ? b[i] : 0; int val = ai - bi - borrow; if (val < 0) { val += 10; borrow = 1; } else { borrow = 0; } res.push_back(val); } // 去掉后导零 while (res.size() > 1 && res.back() == 0) res.pop_back(); return res; } // 将字符串转成 vector<int>(顺序存储) vector<int> strToVec(const string& s) { vector<int> res; for (char ch : s) res.push_back(ch - '0'); return res; } // 主函数:高精度除法(逐位试商法) int main() { string aStr, bStr; cout << "请输入被除数 a(正整数):"; cin >> aStr; cout << "请输入除数 b(正整数,不能为0):"; cin >> bStr; // 处理前导零 aStr = removeLeadingZeros(aStr); bStr = removeLeadingZeros(bStr); if (bStr == "0") { cout << "错误:除数不能为0!" << endl; return 1; } vector<int> a = strToVec(aStr); vector<int> b = strToVec(bStr); vector<int> tempB = b; reverse(tempB.begin(),tempB.end()); vector<int> remainder; // 当前余数 vector<int> quotient; // 商 for (int i = 0; i < a.size(); ++i) { // 把当前位加到余数末尾 顺序存储按高位来 remainder.push_back(a[i]); // 去掉前导零 while (remainder.size() > 1 && remainder[0] == 0) remainder.erase(remainder.begin()); // 试商:从0~9依次尝试 int q = 0; reverse(remainder.begin(),remainder.end()); while (compare(remainder, tempB)) { remainder = subtract(remainder,tempB); q++; } quotient.push_back(q); reverse(remainder.begin(),remainder.end()); //reverse(tempB.begin(),tempB.end()); } // 去掉前导零 while (quotient.size() > 1 && quotient[0] == 0) quotient.erase(quotient.begin()); // 输出结果 cout << "商 = "; for (int digit : quotient) cout << digit; cout << endl; // 处理余数的前导零 while (remainder.size() > 1 && remainder[0] == 0) remainder.erase(remainder.begin()); cout << "余数 = "; for (int digit : remainder) cout << digit; cout << endl; return 0; }
📖 示例运行
输入:
请输入被除数 a(正整数):123456789 请输入除数 b(正整数,不能为0):123
输出:
商 = 1003713 余数 = 78
🧩 关键函数说明
函数名 功能 removeLeadingZeros
去掉字符串前面多余的0 strToVec
将字符串转为顺序存储的 vector compare
判断两个大数是否 a >= b subtract
实现 a - b 的高精度减法 main
中逻辑实现逐位试商的高精度除法
🎨 竖式除法图解(伪代码风格)
初始化余数为空 对于每一位 a_i: 把 a_i 加入余数 从 0 到 9 依次尝试商 直到余数 < b 为止 记录最大可以的商 输出该商
以下是对代码的详细注释和解释,涵盖各个函数的功能、逻辑流程以及关键点:
1. 去掉前导零
string removeLeadingZeros(const string& s) { int i = 0; while (i < s.size() && s[i] == '0') ++i; if (i >= s.size()) return "0"; return s.substr(i); }
- 功能:去除字符串中的前导零。
- 逻辑:
- 遍历字符串,跳过前导零。
- 如果整个字符串都是零(如
"0000"
),返回"0"
。 - 否则,返回去掉前导零后的子字符串。
- 示例:
removeLeadingZeros("00123")
→"123"
removeLeadingZeros("0000")
→"0"
2. 比较两个大数
bool compare(const vector<int>& a, const vector<int>& b) { if (a.size() > b.size()) return true; if (a.size() < b.size()) return false; for (int i = a.size() - 1; i >= 0; --i) { if (a[i] > b[i]) return true; if (a[i] < b[i]) return false; } return true; // 相等 }
- 功能:判断
a >= b
。 - 逻辑:
- 长度比较:若
a
的位数多于b
,则a > b
;反之则a < b
。 - 逐位比较:从高位(向量末尾)到低位(向量开头)依次比较,直到找到差异。
- 长度比较:若
- 关键点:
- 向量的存储顺序是高位在前,低位在后(如
123
存储为[1,2,3]
)。 - 比较逻辑与存储顺序一致,因此正确。
- 向量的存储顺序是高位在前,低位在后(如
3. 大数减法
vector<int> subtract(const vector<int>& a, const vector<int>& b) { vector<int> res; int borrow = 0; for (int i = 0; i < a.size(); ++i) { int ai = a[i]; int bi = (i < b.size()) ? b[i] : 0; int val = ai - bi - borrow; if (val < 0) { val += 10; borrow = 1; } else { borrow = 0; } res.push_back(val); } while (res.size() > 1 && res.back() == 0) res.pop_back(); return res; }
- 功能:计算
a - b
,假设a >= b
。 - 逻辑:
- 从低位到高位处理:向量的存储顺序为高位在前,因此循环从
i=0
到i < a.size()
。 - 借位处理:若当前位结果为负数,借位
1
并调整值。 - 后导零处理:去除结果末尾多余的零(如
100 - 99 = 1
→[1,0,0]
→[1]
)。
- 从低位到高位处理:向量的存储顺序为高位在前,因此循环从
- 关键点:
- 该函数在试商部分使用时,参数
a
和b
已被反转为低位在前的存储顺序,因此处理逻辑正确。 - 例如:
a = [1,2]
(代表12
),b = [2]
(代表2
),反转后为[2,1]
和[2]
,减法结果为[0,9]
(代表9
)。
- 该函数在试商部分使用时,参数
4. 字符串转整数向量
vector<int> strToVec(const string& s) { vector<int> res; for (char ch : s) res.push_back(ch - '0'); return res; }
- 功能:将字符串转换为整数向量。
- 逻辑:
- 按字符顺序转换为数字,存储为高位在前的向量。
- 例如:
"123"
→[1,2,3]
。
5. 主函数:高精度除法(逐位试商法)
int main() { string aStr, bStr; cout << "请输入被除数 a(正整数):"; cin >> aStr; cout << "请输入除数 b(正整数,不能为0):"; cin >> bStr; aStr = removeLeadingZeros(aStr); bStr = removeLeadingZeros(bStr); if (bStr == "0") { cout << "错误:除数不能为0!" << endl; return 1; } vector<int> a = strToVec(aStr); vector<int> b = strToVec(bStr); vector<int> tempB = b; reverse(tempB.begin(), tempB.end()); vector<int> remainder; // 当前余数 vector<int> quotient; // 商 for (int i = 0; i < a.size(); ++i) { remainder.push_back(a[i]); while (remainder.size() > 1 && remainder[0] == 0) remainder.erase(remainder.begin()); // 试商 reverse(remainder.begin(), remainder.end()); int q = 0; while (compare(remainder, tempB)) { remainder = subtract(remainder, tempB); q++; } quotient.push_back(q); reverse(remainder.begin(), remainder.end()); } // 去掉商的前导零 while (quotient.size() > 1 && quotient[0] == 0) quotient.erase(quotient.begin()); // 输出结果 cout << "商 = "; for (int digit : quotient) cout << digit; cout << endl; // 处理余数的前导零 while (remainder.size() > 1 && remainder[0] == 0) remainder.erase(remainder.begin()); cout << "余数 = "; for (int digit : remainder) cout << digit; cout << endl; return 0; }
- 功能:实现高精度除法(逐位试商法)。
- 逻辑流程:
- 输入处理:
- 读取被除数
a
和除数b
。 - 去除前导零,并检查除数是否为零。
- 读取被除数
- 初始化:
- 将
a
和b
转换为整数向量。 tempB
是b
的反转(低位在前),用于试商时的比较和减法。
- 将
- 逐位试商:
- 处理被除数的每一位:
- 将当前位添加到余数末尾,并去除余数的前导零。
- 反转余数和
tempB
(确保存储顺序为低位在前)。 - 试商:通过不断减去
tempB
,直到余数小于tempB
,记录商q
。
- 恢复余数的存储顺序(高位在前),继续处理下一位。
- 处理被除数的每一位:
- 输出结果:
- 去除商和余数的前导零后输出。
- 输入处理:
以下是对您提供的 高精度除法(逐位试商法) 代码的完整注释版本。每一段都加上了清晰的功能说明和逻辑解释,便于理解与维护。
#include <iostream> #include <string> #include <vector> #include <algorithm> using namespace std; // =============================== // 工具函数一:去除字符串前导零 // =============================== // 输入一个字符串,返回去掉前导零后的结果 // 若全是0,则返回"0" string removeLeadingZeros(const string& s) { int i = 0; while (i < s.size() && s[i] == '0') ++i; // 跳过前导零 if (i >= s.size()) return "0"; // 全是0的情况 return s.substr(i); // 返回去掉前导零的子串 } // =============================== // 工具函数二:比较两个大数 a >= b ? // =============================== // 输入两个代表数字的 vector<int>(高位在前) // 返回 true 表示 a >= b bool compare(const vector<int>& a, const vector<int>& b) { if (a.size() > b.size()) return true; // 位数多的大 if (a.size() < b.size()) return false; // 位数少的小 // 位数相同,从高位到低位比较 for (int i = a.size() - 1; i >= 0; --i) { if (a[i] > b[i]) return true; if (a[i] < b[i]) return false; } return true; // 完全相等也返回true } // =============================== // 工具函数三:大数减法 a - b(假设 a >= b) // =============================== // 输入两个 vector<int> 表示的数字(低位在前) // 返回差值(也是低位在前) vector<int> subtract(const vector<int>& a, const vector<int>& b) { vector<int> res; int borrow = 0; for (int i = 0; i < a.size(); ++i) { int ai = a[i]; int bi = (i < b.size()) ? b[i] : 0; // 超出b的部分补0 int val = ai - bi - borrow; if (val < 0) { val += 10; borrow = 1; } else { borrow = 0; } res.push_back(val); } // 去掉后导零(如 [3, 0, 0] -> [3]) while (res.size() > 1 && res.back() == 0) res.pop_back(); return res; } // =============================== // 工具函数四:字符串转为整数向量 // =============================== // 将输入的数字字符串转换成 vector<int>,高位在前 vector<int> strToVec(const string& s) { vector<int> res; for (char ch : s) res.push_back(ch - '0'); return res; } // =============================== // 主函数:实现高精度除法(逐位试商法) // =============================== int main() { string aStr, bStr; cout << "请输入被除数 a(正整数):"; cin >> aStr; cout << "请输入除数 b(正整数,不能为0):"; cin >> bStr; // 处理前导零 aStr = removeLeadingZeros(aStr); bStr = removeLeadingZeros(bStr); if (bStr == "0") { cout << "错误:除数不能为0!" << endl; return 1; } // 转换为整数向量(高位在前) vector<int> a = strToVec(aStr); vector<int> b = strToVec(bStr); // tempB 是反转后的 b(即低位在前),用于试商时比较 vector<int> tempB = b; reverse(tempB.begin(), tempB.end()); vector<int> remainder; // 当前余数(高位在前) vector<int> quotient; // 商 // 模拟列竖式除法过程,逐位处理被除数每一位 for (int i = 0; i < a.size(); ++i) { // 把当前位加到余数末尾(高位在前) remainder.push_back(a[i]); // 去掉前导零(如 [0,0,5] -> [5]) while (remainder.size() > 1 && remainder[0] == 0) remainder.erase(remainder.begin()); // 试商开始: // 将余数反转为低位在前,方便比较和减法操作 reverse(remainder.begin(), remainder.end()); int q = 0; // 不断减去除数 tempB 直到余数小于除数 while (compare(remainder, tempB)) { remainder = subtract(remainder, tempB); q++; } quotient.push_back(q); // 记录当前位的商 // 反转回高位在前,准备下一轮处理 reverse(remainder.begin(), remainder.end()); } // 输出前处理:去掉商的前导零 while (quotient.size() > 1 && quotient[0] == 0) quotient.erase(quotient.begin()); // 输出结果 cout << "商 = "; for (int digit : quotient) cout << digit; cout << endl; // 输出前处理:去掉余数的前导零 while (remainder.size() > 1 && remainder[0] == 0) remainder.erase(remainder.begin()); cout << "余数 = "; for (int digit : remainder) cout << digit; cout << endl; return 0; }
✅ 功能总结:
这个程序实现了高精度除法,支持非常大的整数作为输入,并输出商和余数。主要特点如下:
模块 功能 removeLeadingZeros
去除字符串前导零 compare
判断两个大数大小关系 subtract
高精度减法运算 strToVec
字符串转整数向量 main
实现高精度除法核心逻辑
🧠 存储顺序说明:
- 向量存储方式:高位在前(例如
123
→[1,2,3]
) - 试商阶段需要反转:为了方便减法和比较,临时将数字反转为低位在前(个位在前)
📌 示例输入输出:
输入:
请输入被除数 a(正整数):123456789 请输入除数 b(正整数,不能为0):1234
输出:
商 = 100045 余数 = 999
如果你有更多关于该算法的优化、扩展需求(如支持负数、小数、取模等),也可以继续提问!
关键点总结
- 存储顺序:
- 高位在前:向量默认存储为高位在前(如
123
→[1,2,3]
)。 - 试商时反转:在试商阶段,
remainder
和tempB
被反转为低位在前,确保减法和比较逻辑正确。
- 高位在前:向量默认存储为高位在前(如
- 试商逻辑:
- 通过不断减去
tempB
(反转后的除数),计算当前位的商。 - 每次减法后更新余数,确保余数始终小于除数。
- 通过不断减去
- 前导零处理:
- 商和余数在输出前均去除前导零,确保结果简洁。
- 逻辑正确性:
- 所有函数逻辑与存储顺序一致,无逻辑错误。
示例
- 输入:
请输入被除数 a(正整数):12345 请输入除数 b(正整数,不能为0):678
- 输出:
商 = 18 余数 = 9
结论
代码逻辑正确,能够正确实现高精度除法。其他部分(如存储顺序、试商逻辑、减法处理)均符合高精度除法的要求。
✅ 总结知识点
内容 说明 使用 vector 存储每一位数字,便于处理进退位 高精度减法 自定义实现两个大数相减 除法模拟 通过逐位试商模拟竖式除法 输出方式 顺序打印 vector 中的每一位 支持大数 可以处理任意长度的大整数
🧪 练习建议
你可以试着扩展以下功能:
- [ ] 支持负数输入(带符号判断)
- [ ] 返回值改为结构体,包含商和余数
- [ ] 把结果写入文件保存
- [ ] 加入性能优化(如快速比较、提前终止)
🙋♂️ 如何继续学习?
如果你希望我继续扩展以下内容,请告诉我:
- 如何加入二分试商优化?
- 如何支持保留小数部分?
- 如何把结果保存为文件?
- 如何用类封装高精度库?
😊
📌 结语:
通过本教程,你已经掌握了如何用逐位试商的方式模拟竖式除法的基本方法。这是理解高精度运算的重要一步,也是打牢算法基础的关键环节!需要配套练习题或进阶讲解也可以随时告诉我哦 😊
-
2025-5-16 10:10:36@
C++ 高精度除法教程(零基础版)
在前面的教程中,我们学习了如何用 C++ 实现高精度乘法。现在,让我们来攻克高精度除法这个更具挑战性的问题。高精度除法可以帮助我们处理非常大的数之间的除法运算,这是普通数据类型无法完成的任务。
高精度除法的基本思路
高精度除法比乘法更复杂,主要有两种实现方式:
-
减法模拟法:不断从被除数中减去除数,直到余数小于除数,减的次数就是商。这种方法简单但效率低,适用于除数较小的情况。
-
逐位试商法:模拟手工除法的过程,逐位确定商的值。这是更高效的方法,也是我们本次教程要实现的方法。
手工除法的步骤是这样的:
例如:计算 1234 ÷ 25 049 ______ 25|1234 -0 --- 12 -0 --- 123 ← 取当前的余数 123 -100 ← 25 × 4 = 100(试商 4) ---- 234 ← 余数 23 补上下一位 4,得到 234 -225 ← 25 × 9 = 225(试商 9) ---- 9 ← 最终余数
我们将用代码模拟这个逐位试商的过程。
完整代码实现
下面是高精度除法的完整实现,包含了高精度减法和比较等辅助函数:
#include <iostream> #include <string> #include <vector> #include <algorithm> using namespace std; // 高精度比较:判断 a 是否大于等于 b bool greaterOrEqual(string a, string b) { if (a.length() != b.length()) { return a.length() > b.length(); } return a >= b; } // 高精度减法:计算 a - b,假设 a >= b string subtract(string a, string b) { string res = ""; int borrow = 0; // 借位 int i = a.length() - 1, j = b.length() - 1; while (i >= 0) { int x = a[i] - '0'; int y = (j >= 0) ? b[j] - '0' : 0; int diff = x - y - borrow; if (diff < 0) { diff += 10; borrow = 1; } else { borrow = 0; } res.push_back(diff + '0'); i--; j--; } // 移除前导零 while (res.length() > 1 && res.back() == '0') { res.pop_back(); } // 反转结果 reverse(res.begin(), res.end()); return res; } // 高精度乘法(复用之前教程中的函数) string multiply(string num1, string num2) { if (num1 == "0" || num2 == "0") return "0"; int n = num1.size(); int m = num2.size(); vector<int> result(n + m, 0); for (int i = n - 1; i >= 0; i--) { for (int j = m - 1; j >= 0; j--) { int digit1 = num1[i] - '0'; int digit2 = num2[j] - '0'; int product = digit1 * digit2; int p1 = i + j; int p2 = i + j + 1; int sum = product + result[p2]; result[p2] = sum % 10; result[p1] += sum / 10; } } string res; for (int num : result) { if (!(res.empty() && num == 0)) { res.push_back(num + '0'); } } return res; } // 高精度除法:计算 a ÷ b,返回商和余数 pair<string, string> divide(string a, string b) { if (b == "0") { throw invalid_argument("除数不能为零"); } if (a == "0") { return {"0", "0"}; } if (a == b) { return {"1", "0"}; } if (!greaterOrEqual(a, b)) { return {"0", a}; } string quotient = ""; // 商 string remainder = ""; // 余数 for (char c : a) { // 将当前位添加到余数的末尾 remainder += c; // 尝试找到最大的商位 int q = 0; while (greaterOrEqual(remainder, b)) { remainder = subtract(remainder, b); q++; } // 将当前商位添加到结果中 quotient.push_back(q + '0'); } // 移除商的前导零 while (quotient.length() > 1 && quotient[0] == '0') { quotient = quotient.substr(1); } return {quotient, remainder}; } int main() { string dividend, divisor; cout << "请输入被除数: "; cin >> dividend; cout << "请输入除数: "; cin >> divisor; try { auto [quotient, remainder] = divide(dividend, divisor); cout << "商: " << quotient << endl; cout << "余数: " << remainder << endl; } catch (const invalid_argument& e) { cout << "错误: " << e.what() << endl; } return 0; }
代码详细解释
1. 辅助函数:高精度比较
bool greaterOrEqual(string a, string b) { if (a.length() != b.length()) { return a.length() > b.length(); } return a >= b; }
- 比较两个字符串表示的大数
- 先比较长度,长度大的数更大
- 长度相同时,按字典序比较
2. 辅助函数:高精度减法
string subtract(string a, string b) { string res = ""; int borrow = 0; int i = a.length() - 1, j = b.length() - 1; while (i >= 0) { int x = a[i] - '0'; int y = (j >= 0) ? b[j] - '0' : 0; int diff = x - y - borrow; if (diff < 0) { diff += 10; borrow = 1; } else { borrow = 0; } res.push_back(diff + '0'); i--; j--; } while (res.length() > 1 && res.back() == '0') { res.pop_back(); } reverse(res.begin(), res.end()); return res; }
- 模拟手工减法的过程
- 处理借位,并逐位计算差值
- 最后处理前导零并反转结果
3. 辅助函数:高精度乘法
string multiply(string num1, string num2) { // 复用之前教程中的乘法函数 // ... }
- 直接复用之前教程中的高精度乘法函数
- 用于验证结果或其他扩展功能
4. 核心函数:高精度除法
pair<string, string> divide(string a, string b) { if (b == "0") { throw invalid_argument("除数不能为零"); } if (a == "0") { return {"0", "0"}; } // 处理特殊情况 if (a == b) { return {"1", "0"}; } if (!greaterOrEqual(a, b)) { return {"0", a}; } string quotient = ""; string remainder = ""; for (char c : a) { remainder += c; int q = 0; while (greaterOrEqual(remainder, b)) { remainder = subtract(remainder, b); q++; } quotient.push_back(q + '0'); } while (quotient.length() > 1 && quotient[0] == '0') { quotient = quotient.substr(1); } return {quotient, remainder}; }
- 处理各种边界情况:除数为零、被除数为零等
- 逐位处理被除数,每次处理一位并计算当前的余数
- 使用减法试商,找到当前位的最大可能商值
- 最后处理商的前导零
5. 主函数
int main() { string dividend, divisor; cout << "请输入被除数: "; cin >> dividend; cout << "请输入除数: "; cin >> divisor; try { auto [quotient, remainder] = divide(dividend, divisor); cout << "商: " << quotient << endl; cout << "余数: " << remainder << endl; } catch (const invalid_argument& e) { cout << "错误: " << e.what() << endl; } return 0; }
- 读取用户输入的被除数和除数
- 调用除法函数计算结果
- 输出商和余数,并处理可能的异常
示例运行
请输入被除数: 123456789 请输入除数: 12345 商: 10000 余数: 1789
请输入被除数: 987654321 请输入除数: 9876 商: 100005 余数: 891
复杂度分析
- 时间复杂度:O(n²),其中 n 是被除数的位数。在最坏情况下,每次试商可能需要 O(n) 的时间。
- 空间复杂度:O(n),主要用于存储中间结果。
优化建议
我们实现的是基础版本的高精度除法,在实际应用中可以考虑以下优化:
-
快速试商法:当前方法通过不断减去除数来试商,效率较低。可以使用更高效的试商方法,例如二分查找来确定最大可能的商。
-
Karatsuba 乘法:在处理大数乘法时,可以使用 Karatsuba 算法等快速乘法算法,将时间复杂度降低到 O(n^1.585)。
-
处理负数:扩展算法以支持负数的除法运算。
高精度除法是一个复杂但非常有用的算法,掌握它可以帮助你解决许多普通计算无法处理的问题。通过本教程,你已经学会了如何用 C++ 实现基本的高精度除法,希望这对你的编程学习有所帮助!# C++ 高精度除法教程(零基础版)
在前面的教程中,我们学习了如何用 C++ 实现高精度乘法。现在,让我们来攻克高精度除法这个更具挑战性的问题。高精度除法可以帮助我们处理非常大的数之间的除法运算,这是普通数据类型无法完成的任务。
高精度除法的基本思路
高精度除法比乘法更复杂,主要有两种实现方式:
-
减法模拟法:不断从被除数中减去除数,直到余数小于除数,减的次数就是商。这种方法简单但效率低,适用于除数较小的情况。
-
逐位试商法:模拟手工除法的过程,逐位确定商的值。这是更高效的方法,也是我们本次教程要实现的方法。
手工除法的步骤是这样的:
例如:计算 1234 ÷ 25 049 ______ 25|1234 -0 --- 12 -0 --- 123 ← 取当前的余数 123 -100 ← 25 × 4 = 100(试商 4) ---- 234 ← 余数 23 补上下一位 4,得到 234 -225 ← 25 × 9 = 225(试商 9) ---- 9 ← 最终余数
我们将用代码模拟这个逐位试商的过程。
完整代码实现
下面是高精度除法的完整实现,包含了高精度减法和比较等辅助函数:
#include <iostream> #include <string> #include <vector> #include <algorithm> using namespace std; // 高精度比较:判断 a 是否大于等于 b bool greaterOrEqual(string a, string b) { if (a.length() != b.length()) { return a.length() > b.length(); } return a >= b; } // 高精度减法:计算 a - b,假设 a >= b string subtract(string a, string b) { string res = ""; int borrow = 0; // 借位 int i = a.length() - 1, j = b.length() - 1; while (i >= 0) { int x = a[i] - '0'; int y = (j >= 0) ? b[j] - '0' : 0; int diff = x - y - borrow; if (diff < 0) { diff += 10; borrow = 1; } else { borrow = 0; } res.push_back(diff + '0'); i--; j--; } // 移除前导零 while (res.length() > 1 && res.back() == '0') { res.pop_back(); } // 反转结果 reverse(res.begin(), res.end()); return res; } // 高精度乘法(复用之前教程中的函数) string multiply(string num1, string num2) { if (num1 == "0" || num2 == "0") return "0"; int n = num1.size(); int m = num2.size(); vector<int> result(n + m, 0); for (int i = n - 1; i >= 0; i--) { for (int j = m - 1; j >= 0; j--) { int digit1 = num1[i] - '0'; int digit2 = num2[j] - '0'; int product = digit1 * digit2; int p1 = i + j; int p2 = i + j + 1; int sum = product + result[p2]; result[p2] = sum % 10; result[p1] += sum / 10; } } string res; for (int num : result) { if (!(res.empty() && num == 0)) { res.push_back(num + '0'); } } return res; } // 高精度除法:计算 a ÷ b,返回商和余数 pair<string, string> divide(string a, string b) { if (b == "0") { throw invalid_argument("除数不能为零"); } if (a == "0") { return {"0", "0"}; } if (a == b) { return {"1", "0"}; } if (!greaterOrEqual(a, b)) { return {"0", a}; } string quotient = ""; // 商 string remainder = ""; // 余数 for (char c : a) { // 将当前位添加到余数的末尾 remainder += c; // 尝试找到最大的商位 int q = 0; while (greaterOrEqual(remainder, b)) { remainder = subtract(remainder, b); q++; } // 将当前商位添加到结果中 quotient.push_back(q + '0'); } // 移除商的前导零 while (quotient.length() > 1 && quotient[0] == '0') { quotient = quotient.substr(1); } return {quotient, remainder}; } int main() { string dividend, divisor; cout << "请输入被除数: "; cin >> dividend; cout << "请输入除数: "; cin >> divisor; try { auto [quotient, remainder] = divide(dividend, divisor); cout << "商: " << quotient << endl; cout << "余数: " << remainder << endl; } catch (const invalid_argument& e) { cout << "错误: " << e.what() << endl; } return 0; }
代码详细解释
1. 辅助函数:高精度比较
bool greaterOrEqual(string a, string b) { if (a.length() != b.length()) { return a.length() > b.length(); } return a >= b; }
- 比较两个字符串表示的大数
- 先比较长度,长度大的数更大
- 长度相同时,按字典序比较
2. 辅助函数:高精度减法
string subtract(string a, string b) { string res = ""; int borrow = 0; int i = a.length() - 1, j = b.length() - 1; while (i >= 0) { int x = a[i] - '0'; int y = (j >= 0) ? b[j] - '0' : 0; int diff = x - y - borrow; if (diff < 0) { diff += 10; borrow = 1; } else { borrow = 0; } res.push_back(diff + '0'); i--; j--; } while (res.length() > 1 && res.back() == '0') { res.pop_back(); } reverse(res.begin(), res.end()); return res; }
- 模拟手工减法的过程
- 处理借位,并逐位计算差值
- 最后处理前导零并反转结果
3. 辅助函数:高精度乘法
string multiply(string num1, string num2) { // 复用之前教程中的乘法函数 // ... }
- 直接复用之前教程中的高精度乘法函数
- 用于验证结果或其他扩展功能
4. 核心函数:高精度除法
pair<string, string> divide(string a, string b) { if (b == "0") { throw invalid_argument("除数不能为零"); } if (a == "0") { return {"0", "0"}; } // 处理特殊情况 if (a == b) { return {"1", "0"}; } if (!greaterOrEqual(a, b)) { return {"0", a}; } string quotient = ""; string remainder = ""; for (char c : a) { remainder += c; int q = 0; while (greaterOrEqual(remainder, b)) { remainder = subtract(remainder, b); q++; } quotient.push_back(q + '0'); } while (quotient.length() > 1 && quotient[0] == '0') { quotient = quotient.substr(1); } return {quotient, remainder}; }
- 处理各种边界情况:除数为零、被除数为零等
- 逐位处理被除数,每次处理一位并计算当前的余数
- 使用减法试商,找到当前位的最大可能商值
- 最后处理商的前导零
5. 主函数
int main() { string dividend, divisor; cout << "请输入被除数: "; cin >> dividend; cout << "请输入除数: "; cin >> divisor; try { auto [quotient, remainder] = divide(dividend, divisor); cout << "商: " << quotient << endl; cout << "余数: " << remainder << endl; } catch (const invalid_argument& e) { cout << "错误: " << e.what() << endl; } return 0; }
- 读取用户输入的被除数和除数
- 调用除法函数计算结果
- 输出商和余数,并处理可能的异常
示例运行
请输入被除数: 123456789 请输入除数: 12345 商: 10000 余数: 1789
请输入被除数: 987654321 请输入除数: 9876 商: 100005 余数: 891
复杂度分析
- 时间复杂度:O(n²),其中 n 是被除数的位数。在最坏情况下,每次试商可能需要 O(n) 的时间。
- 空间复杂度:O(n),主要用于存储中间结果。
优化建议
我们实现的是基础版本的高精度除法,在实际应用中可以考虑以下优化:
-
快速试商法:当前方法通过不断减去除数来试商,效率较低。可以使用更高效的试商方法,例如二分查找来确定最大可能的商。
-
Karatsuba 乘法:在处理大数乘法时,可以使用 Karatsuba 算法等快速乘法算法,将时间复杂度降低到 O(n^1.585)。
-
处理负数:扩展算法以支持负数的除法运算。
高精度除法是一个复杂但非常有用的算法,掌握它可以帮助你解决许多普通计算无法处理的问题。通过本教程,你已经学会了如何用 C++ 实现基本的高精度除法,希望这对你的编程学习有所帮助!
-
- 1