前言:在备赛蓝桥杯时,遇到C++处理数值较大的浮点数问题,特此记录一下。
C++ 的 std::string
类使用动态内存分配,其长度可以根据需要动态增加或减少,自动调整内存大小以适应字符串内容的变化。当字符串长度超过当前分配的内存时,std::string
会自动重新分配更大的内存空间以容纳更多字符。这种动态内存管理使得 std::string
在大多数情况下没有长度限制。
数据类型 | 描述 | 大小(字节) | 范围/取值示例 |
---|---|---|---|
bool |
布尔类型,表示真或假 | 1 | true 或 false |
char |
字符类型,通常用于存储 ASCII 字符 | 1 | -128 到 127 或 0 到 255 |
signed char |
有符号字符类型 | 1 | -128 到 127 |
unsigned char |
无符号字符类型 | 1 | 0 到 255 |
short |
短整型 | 2 | -32,768 到 32,767 |
unsigned short |
无符号短整型 | 2 | 0 到 65,535 |
int |
整型 | 4 | -2,147,483,648 到 2,147,483,647 |
unsigned int |
无符号整型 | 4 | 0 到 4,294,967,295 |
long |
长整型 | 4 或 8 | 取决于平台 |
unsigned long |
无符号长整型 | 4 或 8 | 取决于平台 |
long long |
长长整型(C++11 引入) | 8 | -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 |
unsigned long long |
无符号长长整型(C++11 引入) | 8 | 0 到 18,446,744,073,709,551,615 |
float |
单精度浮点数 | 4 | 约 ±3.4e±38(6-7 位有效数字) |
double |
双精度浮点数 | 8 | 约 ±1.7e±308(15 位有效数字) |
long double |
扩展精度浮点数 | 8、12 或 16 | 取决于平台 |
题目:传送门
题解:
cpp
#include<bits/stdc++.h>
using namespace std;
string add(string num1, string num2) {
int carry = 0;
string result;
int i = num1.length() - 1;
int j = num2.length() - 1;
while (i >= 0 || j >= 0 || carry > 0) {
int digit1 = (i >= 0) ? num1[i--] - '0' : 0;
int digit2 = (j >= 0) ? num2[j--] - '0' : 0;
int sum = digit1 + digit2 + carry;
carry = sum / 10;
result += to_string(sum % 10);
}
reverse(result.begin(), result.end());
return result;
}
string multiply(string num1, int num2) {
int carry = 0;
string result;
for (int i = num1.length() - 1; i >= 0; --i) {
int digit = num1[i] - '0';
int product = digit * num2 + carry;
carry = product / 10;
result += to_string(product % 10);
}
if (carry > 0) {
result += to_string(carry);
}
reverse(result.begin(), result.end());
return result;
}
string multiply(string num1, string num2) {
string result = "0";
for (int i = num2.length() - 1; i >= 0; --i) {
string temp = multiply(num1, num2[i] - '0');
temp += string(num2.length() - 1 - i, '0');
result = add(result, temp);
}
return result;
}
int main() {
int n; string d; cin >> n >> d;
size_t pos = d.find('.');
string d1 = d.substr(0, pos);
string d2 = d.substr(pos + 1);
int len_float = d2.size();
string pow2n = "1";
for (int i = 1; i <= n; ++i) pow2n = multiply(pow2n, "2");
d1 = multiply(d1, pow2n);
d2 = multiply(d2, pow2n);
string d2_int = "0";
if(d2.size() != len_float) d2_int = d2.substr(0, d2.size() - len_float);
int x = d2[d2.size() - len_float] - '0';
if (x >= 5) d2_int = add(d2_int, "1");
cout << add(d1, d2_int) << '\n';
return 0;
}
举例说明 :
1. add( string , string )
cpp
string add(string num1, string num2) {
int carry = 0; // 进位
string result; // 存储结果
int i = num1.length() - 1; // num1 的最后一个字符索引
int j = num2.length() - 1; // num2 的最后一个字符索引
while (i >= 0 || j >= 0 || carry > 0) {
int digit1 = (i >= 0) ? num1[i--] - '0' : 0; // 获取 num1 当前位的数字
int digit2 = (j >= 0) ? num2[j--] - '0' : 0; // 获取 num2 当前位的数字
int sum = digit1 + digit2 + carry; // 计算当前位的和
carry = sum / 10; // 更新进位
result += to_string(sum % 10); // 将当前位的结果添加到结果字符串中
}
reverse(result.begin(), result.end()); // 反转结果字符串
return result; // 返回最终结果
}
假设我们要计算 num1 = "123"
和 num2 = "456"
的和。
-
初始化:
-
carry = 0
-
result = ""
-
i = 2
(指向num1
的最后一个字符 '3') -
j = 2
(指向num2
的最后一个字符 '6')
-
-
第一次循环:
-
digit1 = 3
(从num1[2]
) -
digit2 = 6
(从num2[2]
) -
sum = 3 + 6 + 0 = 9
-
carry = 9 / 10 = 0
-
result = "9"
-
-
第二次循环:
-
i = 1
,j = 1
-
digit1 = 2
(从num1[1]
) -
digit2 = 5
(从num2[1]
) -
sum = 2 + 5 + 0 = 7
-
carry = 7 / 10 = 0
-
result = "97"
-
-
第三次循环:
-
i = 0
,j = 0
-
digit1 = 1
(从num1[0]
) -
digit2 = 4
(从num2[0]
) -
sum = 1 + 4 + 0 = 5
-
carry = 5 / 10 = 0
-
result = "975"
-
-
第四次循环:
-
i = -1
,j = -1
-
carry = 0
,循环条件不再满足,退出循环。
-
-
反转结果:
result
在反转后变为"579"
。
-
返回结果:
- 函数返回字符串
"579"
。
- 函数返回字符串
2. multiply(string , int )
cpp
string multiply(string num1, int num2) {
int carry = 0; // 进位
string result; // 存储结果
for (int i = num1.length() - 1; i >= 0; --i) {
int digit = num1[i] - '0'; // 获取当前位的数字
int product = digit * num2 + carry; // 计算当前位的乘积
carry = product / 10; // 更新进位
result += to_string(product % 10); // 将当前位的结果添加到结果字符串中
}
if (carry > 0) {
result += to_string(carry); // 如果还有进位,添加到结果中
}
reverse(result.begin(), result.end()); // 反转结果字符串
return result; // 返回最终结果
}
假设我们要计算 num1 = "123"
和 num2 = 4
的乘积。
-
初始化:
-
carry = 0
-
result = ""
-
-
循环处理每一位:
- 从
num1
的最后一位开始,逐位处理。
- 从
-
第一次循环(i = 2,处理 '3'):
-
digit = 3
(从num1[2]
) -
product = 3 * 4 + 0 = 12
-
carry = 12 / 10 = 1
-
result += to_string(12 % 10) = "2"
(当前结果是 "2")
-
-
第二次循环(i = 1,处理 '2'):
-
digit = 2
(从num1[1]
) -
product = 2 * 4 + 1 = 9
-
carry = 9 / 10 = 0
-
result += to_string(9 % 10) = "2" + "9"
(当前结果是 "29")
-
-
第三次循环(i = 0,处理 '1'):
-
digit = 1
(从num1[0]
) -
product = 1 * 4 + 0 = 4
-
carry = 4 / 10 = 0
-
result += to_string(4 % 10) = "29" + "4"
(当前结果是 "294")
-
-
检查进位:
carry
为 0,因此不需要添加额外的进位。
-
反转结果:
result
在反转后变为"492"
。
-
返回结果:
- 函数返回字符串
"492"
。
- 函数返回字符串