- C++
C++ 高精度的四则运算方法
- 2025-5-13 20:41:01 @
C++ 高精度四则运算教程(通俗易懂,0基础适用)
http://139.224.60.150/discuss/681322e35309f0329ceeeb2e#1746085445133
在C++中,基本的数据类型如 int
、long long
等都有其数值范围的限制。当我们需要处理非常大的整数时,这些数据类型就无能为力了。这时就需要使用高精度算法(也叫大数运算)来模拟手算过程,完成加减乘除等操作。
本教程将从零开始,带你一步步实现高精度的四则运算:加法、减法、乘法和除法。
✅ 前置知识
- 了解C++基本语法
- 会使用
vector
或string
- 了解函数的基本定义与调用
- 使用命名空间:
using namespace std;
🧠 思路说明
我们使用字符串或数组来保存每一位数字,然后像小学列竖式那样进行逐位计算,并处理进位或借位问题。
📦 准备工作:引入头文件 & 命名空间
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
🔢 数据结构设计
我们将每个大整数存储为一个字符型的向量(vector<int>
),其中个位在前,高位在后,便于从低位开始计算。
例如:123456
存储为 {6,5,4,3,2,1}
➕ 高精度加法
💡 原理:列竖式加法 + 进位处理
vector<int> add(const vector<int>& A, const vector<int>& B) {
vector<int> C;
int t = 0; // 进位
for (int i = 0; i < A.size() || i < B.size() || t; ++i) {
if (i < A.size()) t += A[i];
if (i < B.size()) t += B[i];
C.push_back(t % 10);
t /= 10;
}
return C;
}
🧪 示例:
vector<int> A = {1, 2}; // 21
vector<int> B = {9, 8}; // 89
vector<int> C = add(A, B); // 输出应为 110 -> {0,1,1}
➖ 高精度减法
❗ 注意:必须保证 A >= B,否则要处理负号
// 判断A是否大于等于B
bool cmp(const vector<int>& A, const vector<int>& B) {
if (A.size() != B.size()) return A.size() > B.size();
for (int i = A.size()-1; i >=0; --i)
if (A[i] != B[i]) return A[i] > B[i];
return true;
}
vector<int> sub(vector<int> A, vector<int> B) {
vector<int> C;
int t = 0; // 借位
for (int i = 0; i < A.size(); ++i) {
t = A[i] - t;
if (i < B.size()) t -= B[i];
C.push_back((t + 10) % 10);
t = t < 0 ? 1 : 0;
}
// 去掉前导0
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
🧪 示例:
vector<int> A = {3, 2, 1}; // 123
vector<int> B = {1}; // 1
vector<int> C = sub(A, B); // 应输出 122 -> {2,2,1}
✖️ 高精度乘法(单精度)
💡 原理:模拟手算,一位一位相乘并累加
vector<int> mul(const vector<int>& A, int b) {
vector<int> C;
int t = 0;
for (int i = 0; i < A.size() || t; ++i) {
if (i < A.size()) t += A[i] * b;
C.push_back(t % 10);
t /= 10;
}
return C;
}
🧪 示例:
vector<int> A = {3, 2, 1}; // 123
vector<int> C = mul(A, 2); // 246 -> {6,4,2}
➗ 高精度除法(单精度)
💡 原理:从高位到低位依次做除法,记录商和余数
vector<int> div(const vector<int>& A, int b, int& r) {
vector<int> C;
r = 0;
for (int i = A.size() - 1; i >= 0; --i) {
r = r * 10 + A[i];
C.push_back(r / b);
r %= b;
}
reverse(C.begin(), C.end());
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
🧪 示例:
vector<int> A = {6, 4, 2}; // 246
int r;
vector<int> C = div(A, 2, r); // 商为123,余数为0
🔄 输入输出转换函数
为了方便输入输出,我们需要两个辅助函数:
字符串转高精度向量
vector<int> strToVec(string s) {
vector<int> res;
for (int i = s.size()-1; i >=0; --i)
res.push_back(s[i] - '0');
return res;
}
高精度向量转字符串
string vecToStr(vector<int>& v) {
string res;
for (int i = v.size()-1; i >=0; --i)
res += to_string(v[i]);
return res;
}
🧩 完整示例程序:加法演示
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
vector<int> add(const vector<int>& A, const vector<int>& B) {
vector<int> C;
int t = 0;
for (int i = 0; i < A.size() || i < B.size() || t; ++i) {
if (i < A.size()) t += A[i];
if (i < B.size()) t += B[i];
C.push_back(t % 10);
t /= 10;
}
return C;
}
vector<int> strToVec(string s) {
vector<int> res;
for (int i = s.size()-1; i >=0; --i)
res.push_back(s[i] - '0');
return res;
}
string vecToStr(vector<int>& v) {
string res;
for (int i = v.size()-1; i >=0; --i)
res += to_string(v[i]);
return res;
}
int main() {
string a, b;
cout << "请输入两个大整数:" << endl;
cin >> a >> b;
vector<int> A = strToVec(a);
vector<int> B = strToVec(b);
vector<int> sum = add(A, B);
cout << "它们的和是:" << vecToStr(sum) << endl;
return 0;
}
🧮 拓展练习
类型 | 题目 | 难度 |
---|---|---|
加法 | 大数相加 | ⭐ |
减法 | 大数相减 | ⭐⭐ |
乘法 | 大数 × 小数 | |
大数 × 大数 | ⭐⭐⭐ | |
除法 | 大数 ÷ 小数 | ⭐⭐ |
大数 ÷ 大数 | ⭐⭐⭐⭐ |
📌 小结
操作 | 函数名 | 说明 |
---|---|---|
加法 | add() |
支持任意两数相加 |
减法 | sub() |
要求 A ≥ B |
乘法 | mul() |
和小整数相乘 |
除法 | div() |
和小整数相除,返回商和余数 |
🧠 技巧总结
- 倒序存储:个位在前,高位在后,方便对齐计算。
- 去前导0:结果中去掉多余的前导0。
- 比较大小:用于判断减法顺序。
- 封装函数:把每个操作写成函数,方便复用。
如果你已经掌握了上面的内容,恭喜你已经具备了编写任意精度计算器的能力!
🎉 你可以尝试实现一个完整的高精度计算器程序!
📌 提示:可以结合 switch
实现菜单选择不同的运算类型。
如有任何问题,欢迎继续提问!
13 条评论
-
admin SU @ 2025-5-19 20:47:49
#include <iostream> #include <vector> #include <string> #include <algorithm> using namespace std; // 大数除以小数的除法函数 // A为存储大数的数组(逆序存储,个位在索引0),b为小整数,r用于返回余数 vector<int> div(const vector<int>& A, int b, int& r) { vector<int> C; // 存储商的数组 r = 0; // 初始化余数为0 // 从高位到低位遍历大数A的每一位 for (int i = A.size() - 1; i >= 0; --i) { // 将上一步的余数乘以10再加上当前位数字,得到新的被除数 r = r * 10 + A[i]; // 计算当前位的商并添加到结果数组C中 C.push_back(r / b); // 更新余数 r %= b; } // 由于是从高位开始计算,结果数组C是逆序的,将其反转 reverse(C.begin(), C.end()); // 移除前导零(如果有) while (C.size() > 1 && C.back() == 0) C.pop_back(); return C; } // 将字符串表示的大数转换为逆序存储的数组 // 例如 "123" 转换为 [3, 2, 1] vector<int> strToVec(string s) { vector<int> res; for (int i = s.size() - 1; i >= 0; --i) res.push_back(s[i] - '0'); // 将字符转换为数字并添加到数组 return res; } // 将逆序存储的数组转换为字符串表示的大数 // 例如 [3, 2, 1] 转换为 "123" string vecToStr(vector<int>& v) { string res; for (int i = v.size() - 1; i >= 0; --i) res += to_string(v[i]); // 将数字转换为字符并拼接成字符串 return res; } int main() { string a; cout << "请输入一个大整数:" << endl; cin >> a; // 输入大数 int b, r; cout << "请输入一个小整数:" << endl; cin >> b; // 输入小数 // 将字符串形式的大数转换为逆序存储的数组 vector<int> A = strToVec(a); // 执行除法运算,同时得到商和余数 vector<int> sum = div(A, b, r); // 输出商 cout << "它们的商是:" << endl << vecToStr(sum) << endl; // 输出余数 cout << "余数是:" << r << endl; return 0; }
代码功能说明
这段C++ 代码实现了大整数(用字符串表示)除以小整数的功能,具体包括:
div
函数:实现大整数除以小整数的核心逻辑,通过模拟除法运算过程,从高位到低位逐位计算商和余数,最后对结果数组进行反转和去除前导零操作。strToVec
函数:将输入的字符串形式的大整数转换为逆序存储的整数数组,方便后续计算。vecToStr
函数:将表示大整数的逆序数组转换回字符串形式,便于输出结果展示。main
函数:负责与用户交互,获取输入的大整数和小整数,调用上述函数完成除法运算并输出商和余数。
-
2025-5-19 20:46:54@
#include <iostream> #include <vector> #include <string> #include <algorithm> using namespace std; vector<int> div(const vector<int>& A, int b, int& r) { vector<int> C; r = 0; for (int i = A.size() - 1; i >= 0; --i) { r = r * 10 + A[i]; C.push_back(r / b); r %= b; } reverse(C.begin(), C.end()); while (C.size() > 1 && C.back() == 0) C.pop_back(); return C; } vector<int> strToVec(string s) { vector<int> res; for (int i = s.size()-1; i >=0; --i) res.push_back(s[i] - '0'); return res; } string vecToStr(vector<int>& v) { string res; for (int i = v.size()-1; i >=0; --i) res += to_string(v[i]); return res; } int main() { string a; cout << "请输入一个大整数:" << endl; cin >> a; int b,r; cout << "请输入一个小整数:" << endl; cin>>b; vector<int> A = strToVec(a); vector<int> sum = div(A, b,r); cout << "它们的积是:" <<endl<< vecToStr(sum) << endl<<r<<endl; return 0; }
-
2025-5-19 20:26:55@
#include <iostream> #include <vector> #include <string> #include <algorithm> using namespace std; // 大数乘以小数的乘法函数 // A为存储大数的数组(逆序存储,个位在索引0),b为小整数 vector<int> mul(const vector<int>& A, int b) { vector<int> C; // 存储结果的数组 int t = 0; // 进位值 // 遍历A的每一位并处理进位,直到所有位处理完毕且进位为0 for (int i = 0; i < A.size() || t; ++i) { if (i < A.size()) t += A[i] * b; // 累加当前位乘积和进位 C.push_back(t % 10); // 存储当前位结果(取模10) t /= 10; // 更新进位(整除10) } // 移除前导零(如果有) while (C.size() > 1 && C.back() == 0) C.pop_back(); return C; } // 将字符串表示的大数转换为逆序存储的数组 // 例如 "123" 转换为 [3, 2, 1] vector<int> strToVec(string s) { vector<int> res; for (int i = s.size() - 1; i >= 0; --i) res.push_back(s[i] - '0'); // 字符转数字 return res; } // 将逆序存储的数组转换为字符串表示的大数 // 例如 [3, 2, 1] 转换为 "123" string vecToStr(vector<int>& v) { string res; for (int i = v.size() - 1; i >= 0; --i) res += to_string(v[i]); // 数字转字符并拼接 return res; } int main() { string a; cout << "请输入一个大整数:" << endl; cin >> a; // 输入大数 int b; cout << "请输入一个小整数:" << endl; cin >> b; // 输入小数 // 将字符串转换为逆序数组 vector<int> A = strToVec(a); // 执行乘法运算 vector<int> sum = mul(A, b); // 输出结果 cout << "它们的积是:" << endl << vecToStr(sum) << endl; return 0; }
代码功能说明:
这段C++程序实现了高精度整数(大数)与普通整数(小数)的乘法运算,主要功能包括:
- 大数存储:使用
vector<int>
逆序存储大数的每一位(个位在索引0)。 - 字符串转换:通过
strToVec
和vecToStr
函数实现字符串与数值数组的相互转换。 - 乘法运算:
mul
函数模拟竖式乘法,逐位相乘并处理进位,确保高精度计算的正确性。 - 输入输出:提供友好的交互界面,支持用户输入大数和小数,并输出计算结果。
这种实现方式能够处理远超普通数据类型范围的大整数乘法,适用于需要高精度计算的场景。
- 大数存储:使用
-
2025-5-19 20:25:45@
#include <iostream> #include <vector> #include <string> #include <algorithm> using namespace std; vector<int> mul(const vector<int>& A, int b) { vector<int> C; int t = 0; for (int i = 0; i < A.size() || t; ++i) { if (i < A.size()) t += A[i] * b; C.push_back(t % 10); t /= 10; } return C; } vector<int> strToVec(string s) { vector<int> res; for (int i = s.size()-1; i >=0; --i) res.push_back(s[i] - '0'); return res; } string vecToStr(vector<int>& v) { string res; for (int i = v.size()-1; i >=0; --i) res += to_string(v[i]); return res; } int main() { string a; cout << "请输入一个大整数:" << endl; cin >> a; int b; cout << "请输入一个小整数:" << endl; cin>>b; vector<int> A = strToVec(a); vector<int> sum = mul(A, b); cout << "它们的积是:" <<endl<< vecToStr(sum) << endl; return 0; }
-
2025-5-15 21:30:26@
-
2025-5-15 21:27:38@
以下是添加了详细注释的代码,重点解释了高精度减法的逻辑和负数处理机制:
#include <iostream> #include <string> #include <vector> // 使用 vector 必须包含这个头文件 #include <algorithm> using namespace std; // 高精度减法函数:计算两个大整数的差(需保证被减数 >= 减数) vector<int> sub(vector<int> A, vector<int> B); // 字符串比较函数:判断字符串表示的数字 A 是否大于等于 B bool cmp(const string& A, const string& B); // 字符串转数字向量:将字符串形式的大整数转换为低位在前的向量表示 vector<int> strToVec(string s); // 打印数字向量:按高位到低位顺序输出向量表示的大整数 void printVec(vector<int>& v); // 向量转字符串:将低位在前的向量表示转换为高位在前的字符串形式 string vecToStr(vector<int>& v); bool flag = true; // 负数标记:true 表示结果为正,false 表示结果为负 int main() { string s1, s2; cin >> s1 >> s2; // 确保被减数 >= 减数,否则交换并标记负数 if (cmp(s1, s2) == false) { swap(s1, s2); // 交换两个数字字符串 flag = false; // 标记结果为负数 } // 转换字符串为低位在前的数字向量(例如 "123" -> {3,2,1}) vector<int> A = strToVec(s1); vector<int> B = strToVec(s2); // 执行高精度减法(要求 A >= B,结果符号由 flag 控制) vector<int> C = sub(A, B); // 将结果向量转换为字符串 string res = vecToStr(C); // 输出符号(如果结果为负) if (flag == false) { cout << "-"; } cout << res << endl; return 0; } // 判断字符串表示的数字 A 是否大于等于 B bool cmp(const string& A, const string& B) { if (A.size() != B.size()) return A.size() > B.size(); // 长度更长的数字更大 return A >= B; // 长度相同则按字典序比较(字符串直接比较等价于数字大小) } // 高精度减法核心函数(假设 A >= B) vector<int> sub(vector<int> A, vector<int> B) { vector<int> C; // 存储结果(低位在前) int t = 0; // 借位标记:0 表示无借位,1 表示需要借位 // 遍历被减数的每一位(减数长度不足时视为 0) for (int i = 0; i < A.size(); ++i) { // 计算当前位的实际值:被减数当前位 - 借位 - 减数当前位(若存在) t = A[i] - t; if (i < B.size()) t -= B[i]; // 减去减数对应位(若有) // 处理借位:若结果为负数,需借位并调整当前位值 C.push_back((t + 10) % 10); // 当前位结果(加10后取模处理负数) t = t < 0 ? 1 : 0; // 更新借位标记 } // 去除前导零(例如结果为 {0,0,1} 应转为 {1}) while (C.size() > 1 && C.back() == 0) C.pop_back(); // 从末尾删除(向量低位在前,末尾是最高位) return C; } // 字符串转向量:将字符串逆序转换为数字向量(低位在前) vector<int> strToVec(string s) { vector<int> res; for (int i = s.size() - 1; i >= 0; i--) res.push_back(s[i] - '0'); // 字符转数字,低位先存入(例如 '3' 是个位) return res; } // 打印向量:按高位到低位顺序输出(例如 {3,2,1} 输出 "123") void printVec(vector<int>& v) { for (int i = v.size() - 1; i >= 0; i--) cout << v[i]; // 从向量末尾(最高位)开始遍历 cout << endl; } // 向量转字符串:将低位在前的向量转为高位在前的字符串(例如 {0,1,1} -> "110") string vecToStr(vector<int>& v) { string res; for (int i = v.size() - 1; i >= 0; --i) res += to_string(v[i]); // 从最高位开始拼接数字字符 return res; }
关键逻辑解析
-
符号处理:
- 通过
cmp
函数比较两个字符串的大小,若被减数 < 减数,则交换两者并标记flag = false
,最终结果添加负号。 - 注意:此代码仅处理非负数的减法,若输入包含负数需额外扩展(见下方扩展建议)。
- 通过
-
高精度减法核心逻辑:
- 借位处理:
- 当前位计算:
t = A[i] - t - B[i]
(t
为上一位的借位,初始为 0)。 - 若结果为负数(
t < 0
),需向高位借位:当前位值为(t + 10) % 10
,借位标记t = 1
。
- 当前位计算:
- 示例:计算
321 - 123
(向量为A={1,2,3}
,B={3,2,1}
):- 个位:
3 - 0 - 1 = 2
→ 结果2
,无借位。 - 十位:
2 - 0 - 2 = 0
→ 结果0
,无借位。 - 百位:
1 - 0 - 3 = -2
→ 结果(-2 + 10) % 10 = 8
,借位1
(但百位是最高位,借位自动消失)。 - 最终向量为
{8,0,2}
,转换为字符串为208
。
- 个位:
- 借位处理:
-
前导零处理:
- 减法可能产生前导零(如
100 - 99 = 1
),通过while (C.size() > 1 && C.back() == 0)
删除末尾的零(向量末尾是最高位)。
- 减法可能产生前导零(如
扩展建议(处理负数输入)
若需要支持负数减法,可添加以下逻辑:
- 判断输入是否包含负号,提取数值部分。
- 根据符号组合(正正、正负、负正、负负)调用加法或减法:
(-A) - (-B) = B - A
A - (-B) = A + B
(-A) - B = -(A + B)
常见错误避免
- 输入带负号的处理:当前代码假设输入为非负数,若输入包含
-
,需在strToVec
中先去除符号并标记符号位。 - 向量长度差异:减法循环仅遍历被减数长度,减数不足时自动视为 0,无需补零。
- 前导零判断:
C.size() > 1
确保至少保留一个零(如结果为 0 时避免空向量)。
-
-
2025-5-15 21:27:00@
#include<iostream> #include <string> #include <vector> // 使用 vector 必须包含这个头文件 #include <algorithm> using namespace std; vector<int> sub(vector<int> A, vector<int> B); bool cmp(const string& A, const string& B); vector<int> strToVec(string s); void printVec(vector<int>& v); string vecToStr(vector<int>& v); bool flag = true;//负数的标记 int main() { string s1, s2; cin >> s1 >> s2; //必须保证 A >= B,否则要处理负号 if(cmp(s1,s2)==false){ swap(s1,s2); flag = false; } vector<int> A = strToVec(s1); vector<int> B = strToVec(s2); vector<int> C = sub(A, B); // 输出应为 110 -> {0,1,1} string res = vecToStr(C); if(flag == false){ cout<<"-"; } cout<<res<<endl; return 0; } // 判断A是否大于等于B bool cmp(const string& A, const string& B) { if (A.size() != B.size()) return A.size() > B.size(); return A >= B; } vector<int> sub(vector<int> A, vector<int> B) { vector<int> C; int t = 0; // 借位 for (int i = 0; i < A.size(); ++i) { t = A[i] - t; if (i < B.size()) t -= B[i]; C.push_back((t + 10) % 10); t = t < 0 ? 1 : 0; } // 去掉前导0 while (C.size() > 1 && C.back() == 0) C.pop_back(); return C; } vector<int> strToVec(string s) { vector<int> res; for (int i = s.size() - 1; i >= 0; i--) res.push_back(s[i] - '0'); return res; } void printVec(vector<int>& v) { for (int i = v.size() - 1; i >= 0; i--) cout << v[i]; cout << endl; } string vecToStr(vector<int>& v) { string res; for (int i = v.size()-1; i >=0; --i) res += to_string(v[i]);//string to_string(value); // 数转字符串 return res; }
-
2025-5-15 20:53:34@
以下是添加了详细注释的代码:
#include <iostream> #include <string> #include <vector> // 使用 vector 必须包含这个头文件 #include <algorithm> using namespace std; // 高精度加法:计算两个大整数的和 vector<int> add(const vector<int>& A, const vector<int>& B); // 字符串转数字向量:将字符串形式的大整数转换为低位在前的向量表示 vector<int> strToVec(string s); // 打印数字向量:按高位到低位顺序输出向量表示的大整数 void printVec(vector<int>& v); // 向量转字符串:将低位在前的向量表示转换为高位在前的字符串形式 string vecToStr(vector<int>& v); int main() { string s1, s2; cin >> s1 >> s2; // 转换输入字符串为数字向量,低位在前存储(例如"123"转为{3,2,1}) vector<int> A(strToVec(s1)); vector<int> B = strToVec(s2); // 执行高精度加法(例如{3,2,1} + {7,8,9} = {0,1,2,1} 表示 123+987=1110) vector<int> C = add(A, B); // 输出应为 110 -> {0,1,1} // 将结果向量转换为字符串并输出 string res = vecToStr(C); cout << res << endl; return 0; } // 高精度加法实现:逐位相加并处理进位 vector<int> add(const vector<int>& A, const vector<int>& B) { vector<int> C; int t = 0; // 进位值 // 遍历两个向量的每一位,处理到最高位以及可能的进位 for (int i = 0; i < A.size() || i < B.size() || t; ++i) { if (i < A.size()) t += A[i]; // 累加A的当前位 if (i < B.size()) t += B[i]; // 累加B的当前位 C.push_back(t % 10); // 当前位结果(取模) t /= 10; // 计算进位(整除10) } return C; // 返回低位在前的结果向量 } // 字符串转向量:将字符串逆序转换为数字向量(低位在前) vector<int> strToVec(string s) { vector<int> res; // 从字符串末尾向前遍历(即从低位到高位) for (int i = s.size() - 1; i >= 0; i--) res.push_back(s[i] - '0'); // 字符转数字并添加到向量 return res; // 返回低位在前的向量(例如"123"转为{3,2,1}) } // 向量打印:按高位到低位顺序输出 void printVec(vector<int>& v) { // 从向量末尾向前遍历(即从高位到低位) for (int i = v.size() - 1; i >= 0; i--) cout << v[i]; cout << endl; } // 向量转字符串:将低位在前的向量转换为高位在前的字符串 string vecToStr(vector<int>& v) { string res; // 从向量末尾向前遍历(即从高位到低位) for (int i = v.size() - 1; i >= 0; --i) res += to_string(v[i]); // 数字转字符并拼接 return res; // 返回正确顺序的字符串(例如{0,1,1}转为"110") }
代码关键点说明:
-
存储结构:
- 数字向量采用低位在前的存储方式(例如"123"存储为
{3,2,1}
) - 这种方式便于加法时处理进位(直接在末尾追加新位)
- 数字向量采用低位在前的存储方式(例如"123"存储为
-
高精度加法核心逻辑:
for (int i = 0; i < A.size() || i < B.size() || t; ++i)
- 循环条件覆盖两个加数的所有位以及最后的进位
- 逐位相加并处理进位,确保所有位都被计算
-
字符串与向量转换:
strToVec
:反转字符串顺序并转换为数字向量vecToStr
:反转向量顺序并转换为字符串- 两次反转确保最终结果顺序正确
-
输入输出流程:
输入字符串 → 转为低位在前的向量 → 加法运算 → 转为高位在前的字符串 → 输出
这种实现方式通过模拟手工加法的过程,有效处理了超出普通数据类型范围的大整数运算。
-
-
2025-5-15 20:50:57@
在C++中,
to_string()
是一个标准库函数,其主要作用是将数值类型(如整数、浮点数)转换为对应的字符串表示形式。该函数极大地简化了数值与文本之间的转换过程,避免了传统C风格转换(如sprintf
)的复杂性。核心功能
to_string()
可以将以下类型转换为字符串:- 整数类型:
int
、long
、long long
等。 - 浮点类型:
float
、double
、long double
等。
函数原型
#include <string> // 必须包含此头文件 string to_string(int value); // 整数转字符串 string to_string(long value); // 长整型转字符串 string to_string(long long value); // 长长整型转字符串 string to_string(unsigned value); // 无符号整型转字符串 string to_string(unsigned long value); string to_string(unsigned long long value); string to_string(float value); // 单精度浮点型转字符串 string to_string(double value); // 双精度浮点型转字符串 string to_string(long double value); // 长双精度浮点型转字符串
使用示例
1. 整数转字符串
#include <iostream> #include <string> using namespace std; int main() { int num = 12345; string str = to_string(num); // "12345" cout << "整数转字符串: " << str << endl; long long largeNum = 1234567890123LL; string largeStr = to_string(largeNum); // "1234567890123" cout << "长整数转字符串: " << largeStr << endl; }
2. 浮点数转字符串
#include <iostream> #include <string> using namespace std; int main() { double pi = 3.14159; string piStr = to_string(pi); // 默认保留6位小数,结果为 "3.141590" cout << "浮点数转字符串: " << piStr << endl; float small = 0.0001f; string smallStr = to_string(small); // "0.000100" cout << "小浮点数转字符串: " << smallStr << endl; }
注意事项
-
浮点精度问题:
to_string()
默认保留6位小数,可能导致精度丢失或多余的零。例如:double value = 1.23; string s = to_string(value); // "1.230000"
- 若需自定义精度,建议使用
stringstream
或fmt
库:#include <sstream> double value = 1.23; stringstream ss; ss.precision(2); // 设置精度为2位小数 ss << fixed << value; string s = ss.str(); // "1.23"
-
非数值类型无法转换:
to_string()
仅支持数值类型。若需转换自定义类型(如类对象),需自行重载operator<<
或编写转换函数。
-
负数处理:
- 自动处理负号,无需额外操作:
int negative = -42; string s = to_string(negative); // "-42"
- 自动处理负号,无需额外操作:
与其他转换方式的对比
方法 适用场景 示例 to_string()
简单数值转字符串 string s = to_string(123);
stringstream
自定义格式(如精度) ss << fixed << setprecision(2) << 3.14159;
sprintf()
C风格转换(需注意缓冲区) sprintf(buf, "%d", 123);
std::format()
C++20+ 格式化(更强大) string s = std::format("{}", 123);
总结
to_string()
是C++中最便捷的数值转字符串工具,适用于大多数简单场景。它避免了手动处理缓冲区的麻烦,但在需要精确控制格式(如小数位数)时,建议使用stringstream
或std::format
。 - 整数类型:
-
2025-5-15 20:49:45@
在C++中,
vector<int> A(strToVec(s1));
和vector<int> B = strToVec(s2);
这两种初始化方式在功能上是等价的,但在底层机制和语义上存在一些细微差别。核心区别
-
语法形式:
vector<int> A(strToVec(s1));
:直接初始化(Direct Initialization)。vector<int> B = strToVec(s2);
:拷贝初始化(Copy Initialization)。
-
底层机制:
- 直接初始化:直接调用
vector
的构造函数,用strToVec(s1)
的返回值构造A
。 - 拷贝初始化:理论上会先创建一个临时
vector
对象,再通过拷贝构造函数将临时对象复制给B
,但现代编译器通常会优化掉拷贝操作(即 RVO,Return Value Optimization),最终效果与直接初始化相同。
- 直接初始化:直接调用
-
语义差异:
- 直接初始化:更强调“构造”的意图,可调用任何匹配的构造函数(包括接受多个参数的构造函数)。
- 拷贝初始化:更强调“赋值”的意图,要求右侧表达式的类型可隐式转换为目标类型。
示例对比
假设
strToVec
函数返回一个vector<int>
:vector<int> strToVec(const string& s) { // 将字符串转换为 vector<int> return {1, 2, 3}; } // 直接初始化 vector<int> A(strToVec("123")); // 直接构造 A // 拷贝初始化 vector<int> B = strToVec("456"); // 理论上先创建临时对象,再拷贝给 B,但编译器优化后等价于直接构造
关键细节
-
隐式转换限制:
- 拷贝初始化要求右侧表达式的类型必须能隐式转换为
vector<int>
。例如:vector<int> C = {1, 2, 3}; // 合法,列表初始化可隐式转换为 vector vector<int> D = 42; // 非法,int 无法隐式转换为 vector
- 拷贝初始化要求右侧表达式的类型必须能隐式转换为
-
移动语义:
- 如果
strToVec
返回的是右值(如临时对象),拷贝初始化会触发移动构造函数,避免深拷贝:vector<int> E = getVector(); // 若 getVector() 返回临时对象,触发移动构造(效率高)
- 如果
-
性能差异:
- 在现代编译器中,两种初始化方式的性能通常无差别,因为 RVO 会优化掉临时对象的拷贝。
总结
- 功能上:两种方式都能正确初始化
vector
对象。 - 推荐场景:
- 直接初始化:更通用,适用于所有场景,尤其需要显式调用特定构造函数时。
- 拷贝初始化:代码更简洁,适用于简单赋值场景。
实际编程中,建议根据代码风格和可读性选择,但需注意拷贝初始化的隐式转换限制。
-
-
2025-5-15 20:40:20@
#include <iostream> #include <string> #include <vector> // 使用 vector 必须包含这个头文件 #include <algorithm> using namespace std; vector<int> add(const vector<int>& A, const vector<int>& B); vector<int> strToVec(string s); int main() { string s1, s2; cin >> s1 >> s2; vector<int> A(strToVec(s1)); vector<int> B = strToVec(s2); vector<int> C = add(A, B); // 输出应为 110 -> {0,1,1} reverse(C.begin(), C.end()); for (auto i : C) { cout << i; } return 0; } vector<int> add(const vector<int>& A, const vector<int>& B) { vector<int> C; int t = 0; // 进位 for (int i = 0; i < A.size() || i < B.size() || t; ++i) { if (i < A.size()) t += A[i]; if (i < B.size()) t += B[i]; C.push_back(t % 10); t /= 10; } return C; } vector<int> strToVec(string s) { vector<int> res; for (int i = s.size() - 1; i >= 0; i--) res.push_back(s[i] - '0'); return res; }
-
2025-5-15 20:28:37@
#include <iostream> #include <string> #include <vector> // 使用 vector 必须包含这个头文件 #include <algorithm> using namespace std; vector<int> add(const vector<int>& A, const vector<int>& B); int main() { //string ss; //cin >> ss; //cout<<ss; vector<int> A = {1, 2}; // 21 vector<int> B = {9, 8}; // 89 vector<int> C = add(A, B); // 输出应为 110 -> {0,1,1} reverse(C.begin(), C.end()); for (auto i : C) { cout << i; } return 0; } vector<int> add(const vector<int>& A, const vector<int>& B) { vector<int> C; int t = 0; // 进位 for (int i = 0; i < A.size() || i < B.size() || t; ++i) { if (i < A.size()) t += A[i]; if (i < B.size()) t += B[i]; C.push_back(t % 10); t /= 10; } return C; }
-
2025-5-13 20:42:09@
C++高精度四则运算教程
在C++中,基本数据类型(如int、long long)有数值范围限制。当需要处理极大或极小数时,就需要自己实现高精度运算。本教程将从零开始教你如何用C++实现高精度的加、减、乘、除运算。
1. 高精度加法
高精度加法的核心是模拟竖式加法,逐位相加并处理进位。
下面是完整实现代码:
#include <iostream> #include <string> #include <algorithm> using namespace std; // 使用标准命名空间,避免重复写std:: // 高精度加法函数 string add(string num1, string num2) { string result; int carry = 0; // 进位 int i = num1.size() - 1; int j = num2.size() - 1; // 逐位相加 while (i >= 0 || j >= 0 || carry > 0) { int sum = carry; if (i >= 0) sum += num1[i--] - '0'; if (j >= 0) sum += num2[j--] - '0'; result.push_back(sum % 10 + '0'); // 当前位结果 carry = sum / 10; // 计算进位 } reverse(result.begin(), result.end()); // 反转字符串得到正确结果 return result; } int main() { string num1, num2; cout << "请输入两个大整数:" << endl; cin >> num1 >> num2; string sum = add(num1, num2); cout << "两数之和为:" << sum << endl; return 0; }
代码解释:
- 将数字作为字符串处理,避免数值溢出
- 从最低位开始逐位相加,处理进位
- 最后反转字符串得到正确结果
2. 高精度减法
高精度减法的核心是模拟竖式减法,逐位相减并处理借位。
#include <iostream> #include <string> #include <algorithm> using namespace std; // 判断num1是否大于等于num2 bool isGreaterOrEqual(string num1, string num2) { if (num1.size() != num2.size()) return num1.size() > num2.size(); return num1 >= num2; } // 高精度减法函数 string subtract(string num1, string num2) { if (!isGreaterOrEqual(num1, num2)) return "-" + subtract(num2, num1); string result; int borrow = 0; // 借位 int i = num1.size() - 1; int j = num2.size() - 1; // 逐位相减 while (i >= 0) { int diff = (num1[i] - '0') - borrow; if (j >= 0) diff -= (num2[j] - '0'); if (diff < 0) { diff += 10; borrow = 1; } else { borrow = 0; } result.push_back(diff + '0'); i--; j--; } // 去除前导零 while (result.size() > 1 && result.back() == '0') result.pop_back(); reverse(result.begin(), result.end()); return result; } int main() { string num1, num2; cout << "请输入两个大整数:" << endl; cin >> num1 >> num2; string diff = subtract(num1, num2); cout << "两数之差为:" << diff << endl; return 0; }
代码解释:
- 先判断两数大小关系,处理负数情况
- 逐位相减并处理借位
- 最后去除结果中的前导零
3. 高精度乘法
高精度乘法模拟竖式乘法,将乘数的每一位与被乘数相乘,再累加结果。
#include <iostream> #include <string> #include <vector> #include <algorithm> using namespace std; // 高精度乘法函数 string multiply(string num1, string num2) { if (num1 == "0" || num2 == "0") return "0"; vector<int> result(num1.size() + num2.size(), 0); // 逐位相乘 for (int i = num1.size() - 1; i >= 0; i--) { for (int j = num2.size() - 1; j >= 0; j--) { int mul = (num1[i] - '0') * (num2[j] - '0'); int sum = mul + result[i + j + 1]; result[i + j + 1] = sum % 10; result[i + j] += sum / 10; } } // 转换为字符串 string product; for (int num : result) { if (!(product.empty() && num == 0)) product.push_back(num + '0'); } return product; } int main() { string num1, num2; cout << "请输入两个大整数:" << endl; cin >> num1 >> num2; string product = multiply(num1, num2); cout << "两数之积为:" << product << endl; return 0; }
代码解释:
- 使用数组存储中间结果,避免溢出
- 双重循环处理每一位的乘法
- 累加中间结果并处理进位
- 最后转换为字符串并去除前导零
4. 高精度除法(整数除法)
高精度除法计算两数的商,采用试商的方法逐位确定商的每一位。
#include <iostream> #include <string> #include <algorithm> using namespace std; // 判断num1是否大于等于num2 bool isGreaterOrEqual(string num1, string num2) { if (num1.size() != num2.size()) return num1.size() > num2.size(); return num1 >= num2; } // 高精度减法(辅助函数) string subtract(string num1, string num2) { if (!isGreaterOrEqual(num1, num2)) return "0"; string result; int borrow = 0; int i = num1.size() - 1; int j = num2.size() - 1; while (i >= 0) { int diff = (num1[i] - '0') - borrow; if (j >= 0) diff -= (num2[j] - '0'); if (diff < 0) { diff += 10; borrow = 1; } else { borrow = 0; } result.push_back(diff + '0'); i--; j--; } while (result.size() > 1 && result.back() == '0') result.pop_back(); reverse(result.begin(), result.end()); return result; } // 高精度除法函数(整数除法) pair<string, string> divide(string dividend, string divisor) { if (divisor == "0") throw invalid_argument("除数不能为零"); if (dividend == "0") return {"0", "0"}; string quotient; string remainder = ""; for (char digit : dividend) { remainder += digit; // 试商 int q = 0; while (isGreaterOrEqual(remainder, divisor)) { remainder = subtract(remainder, divisor); q++; } quotient.push_back(q + '0'); } // 去除商的前导零 while (quotient.size() > 1 && quotient[0] == '0') quotient.erase(0, 1); return {quotient, remainder}; } int main() { string dividend, divisor; cout << "请输入被除数和除数:" << endl; cin >> dividend >> 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