高精度算法详解:从原理到加减乘除的完整实现

文章目录

  • 一、为什么需要高精度算法
  • 二、高精度算法的数据结构设计
    • 2.1 基础工具函数
    • 2.2 高精度加法实现
    • 2.3 高精度减法实现
    • 2.4 高精度乘法实现
    • 2.5 高精度除法实现
  • 三、完整测试程序
  • 四、总结

一、为什么需要高精度算法

在编程中,处理极大数值是常见需求,例如:

  • 密码学中的大数运算(如 RSA 算法中的模幂运算)
  • 科学计算中的高精度数值计算
  • 财务系统中的金额处理
  • 数学竞赛中的大数问题求解

C++ 的原生数据类型(如long long)有固定数值范围限制(通常最大约 9×10^18),无法处理任意大小的整数。高精度算法通过将大数字拆分为多个小单元处理,以字符串或数组存储每一位数字,模拟手工计算实现各种运算。

二、高精度算法的数据结构设计

在 C++ 中,我们可以通过纯函数的方式实现高精度算法,避免使用类封装,使代码更加简洁直接。以下是各个核心功能的实现:

2.1 基础工具函数

首先实现一些基础工具函数,用于处理字符串表示的大数:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <stdexcept>// 反转字符串
std::string reverse(const std::string& s) {return std::string(s.rbegin(), s.rend());
}// 去除前导零
std::string removeLeadingZeros(const std::string& num) {int i = 0;while (i < num.size() - 1 && num[i] == '0') {i++;}return num.substr(i);
}// 判断是否为负数
bool isNegative(const std::string& num) {return num[0] == '-';
}// 获取绝对值
std::string getAbs(const std::string& num) {return isNegative(num) ? num.substr(1) : num;
}// 比较两个非负数字的大小
bool absGreaterOrEqual(const std::string& a, const std::string& b) {if (a.length() != b.length()) {return a.length() > b.length();}return a >= b;
}

2.2 高精度加法实现

高精度加法的核心思路是模拟手工加法运算,从低位到高位逐位相加并处理进位:

// 高精度加法
std::string add(const std::string& a, const std::string& b) {// 处理符号if (isNegative(a) && !isNegative(b)) {return subtract(b, getAbs(a));}if (!isNegative(a) && isNegative(b)) {return subtract(a, getAbs(b));}if (isNegative(a) && isNegative(b)) {return "-" + add(getAbs(a), getAbs(b));}// 两个正数相加std::string result;int carry = 0;int i = a.size() - 1;int j = b.size() - 1;while (i >= 0 || j >= 0 || carry > 0) {int sum = carry;if (i >= 0) sum += a[i--] - '0';if (j >= 0) sum += b[j--] - '0';result.push_back((sum % 10) + '0');carry = sum / 10;}return removeLeadingZeros(reverse(result));
}

2.3 高精度减法实现

高精度减法比加法更复杂,需要考虑借位和数字大小比较:

// 高精度减法
std::string subtract(const std::string& a, const std::string& b) {// 处理符号if (isNegative(a) && !isNegative(b)) {return "-" + add(getAbs(a), b);}if (!isNegative(a) && isNegative(b)) {return add(a, getAbs(b));}if (isNegative(a) && isNegative(b)) {return subtract(getAbs(b), getAbs(a));}// 两个正数相减if (!absGreaterOrEqual(a, b)) {return "-" + subtract(b, a);}std::string result;int borrow = 0;int i = a.size() - 1;int j = b.size() - 1;while (i >= 0) {int diff = (a[i] - '0') - borrow;if (j >= 0) diff -= (b[j] - '0');if (diff < 0) {diff += 10;borrow = 1;} else {borrow = 0;}result.push_back(diff + '0');i--;j--;}return removeLeadingZeros(reverse(result));
}

2.4 高精度乘法实现

高精度乘法通常采用竖式乘法的思路,时间复杂度为 O (n²):

// 高精度乘法
std::string multiply(const std::string& a, const std::string& b) {// 处理零的情况if (a == "0" || b == "0") {return "0";}// 处理符号bool isNegative = (isNegative(a) && !isNegative(b)) || (!isNegative(a) && isNegative(b));std::string absA = getAbs(a);std::string absB = getAbs(b);// 结果数组,长度为两数位数之和std::vector<int> result(absA.size() + absB.size(), 0);// 竖式乘法核心逻辑for (int i = absA.size() - 1; i >= 0; i--) {for (int j = absB.size() - 1; j >= 0; j--) {int product = (absA[i] - '0') * (absB[j] - '0');int sum = product + result[i + j + 1];result[i + j + 1] = sum % 10;result[i + j] += sum / 10;}}// 转换结果数组为字符串std::string resultStr;for (int num : result) {if (!(resultStr.empty() && num == 0)) {resultStr.push_back(num + '0');}}return (isNegative ? "-" : "") + resultStr;
}

2.5 高精度除法实现

高精度除法是最复杂的运算,这里采用试商法实现:

// 高精度除法
std::string divide(const std::string& a, const std::string& b) {// 处理除数为零的情况if (b == "0") {throw std::runtime_error("Division by zero");}// 处理零的情况if (a == "0") {return "0";}// 处理符号bool isNegative = (isNegative(a) && !isNegative(b)) || (!isNegative(a) && isNegative(b));std::string absA = getAbs(a);std::string absB = getAbs(b);// 处理被除数小于除数的情况if (!absGreaterOrEqual(absA, absB)) {return "0";}// 试商法核心逻辑std::string quotient;std::string remainder;for (char c : absA) {remainder += c;remainder = removeLeadingZeros(remainder);int count = 0;while (absGreaterOrEqual(remainder, absB)) {remainder = subtract(remainder, absB);count++;}quotient += std::to_string(count);}quotient = removeLeadingZeros(quotient);return (isNegative ? "-" : "") + quotient;
}// 高精度取模
std::string mod(const std::string& a, const std::string& b) {if (b == "0") {throw std::runtime_error("Modulo by zero");}if (a == "0") {return "0";}bool isNegative = isNegative(a);std::string absA = getAbs(a);std::string absB = getAbs(b);if (!absGreaterOrEqual(absA, absB)) {return a;}std::string quotient = divide(absA, absB);std::string product = multiply(quotient, absB);std::string remainder = subtract(absA, product);return (isNegative ? "-" : "") + remainder;
}

三、完整测试程序

下面是一个完整的测试程序,展示如何使用上述高精度算法:

// 测试程序
int main() {try {// 测试加法std::cout << "加法测试: 12345 + 67890 = " << add("12345", "67890") << std::endl;// 测试减法std::cout << "减法测试: 98765 - 12345 = " << subtract("98765", "12345") << std::endl;// 测试乘法std::cout << "乘法测试: 1234 * 5678 = " << multiply("1234", "5678") << std::endl;// 测试除法std::cout << "除法测试: 123456789 / 12345 = " << divide("123456789", "12345") << std::endl;// 测试取模std::cout << "取模测试: 123456789 % 12345 = " << mod("123456789", "12345") << std::endl;// 测试负数运算std::cout << "负数测试:" << std::endl;std::cout << "-123 + 456 = " << add("-123", "456") << std::endl;std::cout << "123 - (-456) = " << subtract("123", "-456") << std::endl;std::cout << "-123 * (-456) = " << multiply("-123", "-456") << std::endl;std::cout << "-12345 / 67 = " << divide("-12345", "67") << std::endl;} catch (const std::exception& e) {std::cerr << "错误: " << e.what() << std::endl;return 1;}return 0;
}

四、总结

高精度算法是处理大数运算的基础,其核心在于:

  • 将大数字拆分为小单元处理
  • 模拟手工计算过程(进位、借位、试商等)
  • 合理处理符号和边界情况

理解高精度算法不仅有助于解决实际问题,还能加深对数字运算本质的理解。在密码学、科学计算等领域,高精度算法更是不可或缺的基础工具。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/web/83620.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

排序--计数排序

一,引言 计数排序是一种针对整数数据的高效排序算法。其主要流程可分为三个步骤&#xff1a;首先计算整数数据的数值范围&#xff1b;接着按大小顺序统计各数值的出现次数&#xff1b;最后根据统计结果输出排序后的数据序列。 二,求最值 遍历现有数据&#xff0c;获取最大值…

Kubernetes安全机制深度解析(四):动态准入控制和Webhook

#作者&#xff1a;程宏斌 文章目录 动态准入控制什么是准入 Webhook&#xff1f; 尝试准入Webhook先决条件编写一个准入 Webhook 服务器部署准入 Webhook 服务即时配置准入 Webhook对 API 服务器进行身份认证 Webhook 请求与响应Webhook 配置匹配请求-规则匹配请求&#xff1a…

WDK 10.0.19041.685,可在32位win7 sp1系统下搭配vs2019使用,可以编译出xp驱动。

(14)[驱动开发]配置环境 VS2019 WDK10 写 xp驱动 (14)[驱动开发]配置环境 VS2019 WDK10 写 xp驱动_microsoft visual 2019 wdk-CSDN博客文章浏览阅读3k次&#xff0c;点赞8次&#xff0c;收藏17次。本文介绍了如何在VS2019环境下安装和配置Windows Driver Kit(WDK)&#xff0…

论坛系统自动化测试

1、项目背景与测试目标 系统定位 论坛系统作为典型的高并发Web应用&#xff0c;需支持用户注册、登录、发帖、评论、私信及个人中心管理等核心功能&#xff0c;是用户公开交流与信息共享的核心平台。其稳定性与响应效率直接影响用户体验及平台活跃度。 测试必要性 功能可靠性&…

ChipWhisperer教程(一)

一、ChipWhisperer介绍 ChipWhisperer 是一个完整的开源工具链&#xff0c;用于学习嵌入式设备上的侧信道攻击并验证这些设备的侧信道抗性。ChipWhisperer主要用于功耗分析&#xff0c;利用设备功耗泄露的信息进行攻击&#xff0c;也可用于故障攻击&#xff08;电压和时钟毛刺…

【持续更新】计算机网络试题

问题1 请简要说明TCP/IP协议栈的四层结构&#xff0c;并分别举出每一层出现的典型协议或应用。 答案 应用层&#xff1a;ping,telnet,dns 传输层&#xff1a;tcp,udp 网络层&#xff1a;ip,icmp 数据链路层&#xff1a;arp,rarp 问题2 下列协议或应用分别属于TCP/IP协议…

短剧系统开发:打造高效、创新的短视频娱乐平台 - 从0到1的完整解决方案

一、短剧市场迎来爆发式增长 - 不容错过的万亿级蓝海 随着5G技术的普及和移动互联网的深度渗透&#xff0c;短剧市场正在经历前所未有的爆发式增长。根据权威机构艾瑞咨询最新发布的《2023年中国网络短剧行业发展报告》显示&#xff1a; 市场规模&#xff1a;2023年中国短剧市…

ChipWhisperer教程(三)

——CW305目标板的波形采集 一、目标板介绍 CW305 是一款独立的 FPGA 目标板&#xff0c;搭载的FPGA芯片为Xilinx Artix-7系列。 它具有与 FPGA 通信的 USB 接口、为 FPGA 提供时钟的外部 PLL、编程 VCC-INT 电源以及用于故障注入环境的二极管保护。 CW305 电路板有多种配置&…

django中如何解析content-type=application/json的请求

django中如何解析content-typeapplication/json的请求 本文由「大千AI助手」原创发布&#xff0c;专注用真话讲AI&#xff0c;回归技术本质。拒绝神话或妖魔化。搜索「大千AI助手」关注我&#xff0c;一起撕掉过度包装&#xff0c;学习真实的AI技术&#xff01; 往期文章回顾: …

Chainlink VRF 深度解析与实战

背景 在区块链的去中心化应用中&#xff0c;随机性是一个常见但难以实现的需求。例如&#xff0c;区块链游戏需要随机决定战斗结果&#xff0c;NFT 项目需要随机分配稀有属性&#xff0c;去中心化抽奖需要公平选择获奖者。然而&#xff0c;传统的链上随机数生成方法&#xff0…

7. TypeScript接口

TypeScript 中的接口&#xff08;Interfaces&#xff09;用于定义对象的结构。它们允许开发者指定一个对象应具有哪些属性以及这些属性的类型。接口有助于确保对象遵循特定的结构&#xff0c;从而在整个应用中提供一致性&#xff0c;并提升代码的可维护性。 一、认识接口 Typ…

UE 新版渲染器输出视频

安装包解压到C盘 打开UE插件 Movie Render Queue 进入UE引擎在项目设置找到 libx264 aac mp4 影片渲染队列调用出 命令行编码器安装包路径&#xff0c;序列输出路径&#xff0c;定序器不能有中文

基于用户的协同过滤推荐算法实现(Java电商平台)

在电商平台中&#xff0c;基于用户的协同过滤推荐算法是一种常见的推荐系统方法。它通过分析用户之间的相似性来推荐商品。以下是一个简单的实现思路和示例代码&#xff0c;使用Java语言。 实现思路 数据准备&#xff1a;收集用户的评分数据&#xff0c;通常以用户-商品评分矩…

LeetCode - 904. 水果成篮

题目 904. 水果成篮 - 力扣&#xff08;LeetCode&#xff09; 思路 题目本质 你有一个整数数组&#xff0c;每个元素代表一种水果。你只能用两个篮子&#xff0c;每个篮子只能装一种水果。你要在数组中找一个最长的连续子数组&#xff0c;这个子数组里最多只包含两种不同的…

发现 Kotlin MultiPlatform 的一点小变化

最近发现 Kotlin 官方已经开始首推 Idea 的社区版的 KMP 插件了. 以前有网页创建 KMP 的项目的文档也消失了. 虽然有 Android Studio 的选项. 但是却不是在默认的位置上了. 足以说明官方是有意想让大家直接使用 Idea 社区版或者专业版 所以我直接在社区版上安装 KMP 插件. 尝试…

【Photoshop】金属字体制作

新建一个空白项目&#xff0c;选择横排文字工具&#xff0c;输入想要的文件建立文字图层 选择横排文字工具选择出文字内容&#xff0c;在通知栏出点击’拾色器‘&#xff0c;设置好需要的文字颜色 图层面板右下角点击‘添加图层样式’&#xff0c;选择斜面和浮雕 样式设置为内斜…

centos 7.9 升级ssh版本 7.4p1 升级到 8.2p1

centos 7.9 升级ssh版本 7.4p1 升级到 8.2p1 1、安装包下载2、安装telnet3、安装openssl-OpenSSL_1_1_1f.tar.gz4、安装openssh-8.2p1.tar.gz5、修改ssh服务的相关配置文件6、确定可以ssh连接服务器后&#xff0c;卸载telnet&#xff0c;因为telnet不安全 本文是离线环境下升级…

stm32---dma串口发送+fifo队列框架

之前分享了一个关于gd32的fifo框架&#xff0c;这次就用stm32仿照写一个&#xff0c;其实几乎一样&#xff0c;这次说的更详细点&#xff0c;我全文都写上了注释&#xff0c;大家直接cv模仿我的调用方式即可 uasrt.c #include "stm32f10x.h" // D…

【生产就曲篇】让应用可观测:Actuator监控端点与日志最佳实践

摘要 本文是《Spring Boot 实战派》系列的终章&#xff0c;我们将探讨如何让应用真正达到**“生产就绪” (Production-Ready)** 的标准。文章的核心是可观测性 (Observability)&#xff0c;即从外部了解一个系统内部运行状态的能力。 我们将深度挖掘 Spring Boot Actuator 的…

操作系统知识(1)

操作系统的分类总结 1、批处理操作系统:单道批处理和多道批处理(主机与外设可并行) 2、分时操作系统:一个计算机系统与多个终端设备连接。将CPU的工作时间划分为许多很短的时间片&#xff0c;轮流为各个终端的用户服务。 3、实时操作系统:实时是指计算机对于外来信息能够以足…