当前位置: 首页 > news >正文

C++中高精度运算问题

前言:在备赛蓝桥杯时,遇到C++处理数值较大的浮点数问题,特此记录一下。

C++ 的 std::string 类使用动态内存分配,其长度可以根据需要动态增加或减少,自动调整内存大小以适应字符串内容的变化。当字符串长度超过当前分配的内存时,std::string 会自动重新分配更大的内存空间以容纳更多字符。这种动态内存管理使得 std::string 在大多数情况下没有长度限制。

数据类型描述大小(字节)范围/取值示例
bool布尔类型,表示真或假1true 或 false
char字符类型,通常用于存储 ASCII 字符1-128 到 127 或 0 到 255
signed char有符号字符类型1-128 到 127
unsigned char无符号字符类型10 到 255
short短整型2-32,768 到 32,767
unsigned short无符号短整型20 到 65,535
int整型4-2,147,483,648 到 2,147,483,647
unsigned int无符号整型40 到 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 引入)80 到 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取决于平台

题目:传送门

题解:

#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 )

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" 的和。

  1. 初始化

    • carry = 0

    • result = ""

    • i = 2 (指向 num1 的最后一个字符 ‘3’)

    • j = 2 (指向 num2 的最后一个字符 ‘6’)

  2. 第一次循环

    • digit1 = 3 (从 num1[2])

    • digit2 = 6 (从 num2[2])

    • sum = 3 + 6 + 0 = 9

    • carry = 9 / 10 = 0

    • result = "9"

  3. 第二次循环

    • i = 1j = 1

    • digit1 = 2 (从 num1[1])

    • digit2 = 5 (从 num2[1])

    • sum = 2 + 5 + 0 = 7

    • carry = 7 / 10 = 0

    • result = "97"

  4. 第三次循环

    • i = 0j = 0

    • digit1 = 1 (从 num1[0])

    • digit2 = 4 (从 num2[0])

    • sum = 1 + 4 + 0 = 5

    • carry = 5 / 10 = 0

    • result = "975"

  5. 第四次循环

    • i = -1j = -1

    • carry = 0,循环条件不再满足,退出循环。

  6. 反转结果

    • result 在反转后变为 "579"

  7. 返回结果

    • 函数返回字符串 "579"

2. multiply(string ,  int )

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 的乘积。

  1. 初始化

    • carry = 0

    • result = ""

  2. 循环处理每一位

    • 从 num1 的最后一位开始,逐位处理。

  3. 第一次循环(i = 2,处理 '3’):

    • digit = 3 (从 num1[2])

    • product = 3 * 4 + 0 = 12

    • carry = 12 / 10 = 1

    • result += to_string(12 % 10) = "2" (当前结果是 “2”)

  4. 第二次循环(i = 1,处理 '2’):

    • digit = 2 (从 num1[1])

    • product = 2 * 4 + 1 = 9

    • carry = 9 / 10 = 0

    • result += to_string(9 % 10) = "2" + "9" (当前结果是 “29”)

  5. 第三次循环(i = 0,处理 '1’):

    • digit = 1 (从 num1[0])

    • product = 1 * 4 + 0 = 4

    • carry = 4 / 10 = 0

    • result += to_string(4 % 10) = "29" + "4" (当前结果是 “294”)

  6. 检查进位

    • carry 为 0,因此不需要添加额外的进位。

  7. 反转结果

    • result 在反转后变为 "492"

  8. 返回结果

    • 函数返回字符串 "492"

相关文章:

  • QT工程建立
  • JavaWeb餐厅点餐系统
  • c++中虚函数(virtual),重写(override),多态(重点介绍动态多态)
  • 《野史未必假》王磊
  • 视频分类的深度学习模型改为回归模型
  • turtle图形化编程等级考试考点汇总(适用于青少年编程学习)
  • 【数据分享】1999—2023年地级市的文化/体育/卫生/社会保障等公服设施相关指标(Shp/Excel格式)
  • 谷歌 AI 协作科学家
  • 【C++】多态详解
  • 告别过去,奔向未来
  • 8. RabbitMQ 消息队列 + 结合配合 Spring Boot 框架实现 “发布确认” 的功能
  • 在线oj平台测试报告(持续更新中)
  • 004_分支结构
  • 一个基于ragflow的工业文档智能解析和问答系统
  • 【AI提示词】学术论文阅读总结
  • FATFS备忘
  • MySQL——DQL的多表查询
  • 【谷歌设置】chrome打开页面在新tab设置(新版)
  • 基于高云fpga实现的fir串行滤波器
  • C语言【删除前导空格】
  • 黑苹果做网站开发吗/搭建网站费用是多少
  • 上海企业网站/发布新闻最快的网站
  • 域名备案与网站备案的区别/威海网站制作
  • 做代练网站能备案/搜索引擎网站排名
  • 网站空间换了 使用原有域名/关于普通话的手抄报
  • 有没有可以做各种字体的网站/全国各城市感染高峰进度查询