「C++」论高精度
大家好,我是Charzie。在编程领域,高精度计算是一个常见的问题。当标准的整型或浮点型无法满足我们的计算需求时,高精度计算就显得尤为重要。在C++中,虽然标准库没有直接提供高精度数据类型,但我们可以通过一些技巧和工具类来实现高精度计算。
为什么需要高精度?
在编程中,我们经常会遇到一些大数计算的问题,比如大数的加减乘除、大素数判断等。这些问题的标准数据类型(如int、long long等)往往无法处理,因为它们有数据范围的限制。此时,我们就需要使用高精度计算来解决问题。
C++中实现高精度的方法
在C++中,实现高精度计算的方法主要有两种:使用数组模拟和使用高精度库。
使用数组模拟
我们可以使用数组来模拟高精度数。每个数组元素存储高精度数的一位,然后通过模拟手工计算的过程来实现高精度计算。这种方法虽然比较繁琐,但能够很好地理解高精度计算的原理。
例如,对于高精度加法,我们可以从低位到高位依次相加,注意处理进位问题。对于高精度乘法,我们可以使用竖式乘法的思想,将两个高精度数相乘的结果逐位计算并存储。
使用高精度库
为了简化高精度计算的实现,我们可以使用一些现成的高精度库,如GMP(GNU Multiple Precision Arithmetic Library)或Boost.Multiprecision库。这些库提供了丰富的高精度数据类型和运算函数,可以大大简化高精度计算的实现。
例如,使用GMP库,我们可以直接定义高精度整数类型,并进行加减乘除等运算,而无需关心底层的实现细节。
高精度计算的应用场景
高精度计算在很多领域都有广泛的应用,比如密码学、大数据分析、科学计算等。在密码学中,高精度计算可以用于实现公钥密码算法中的大数运算;在大数据分析中,高精度计算可以帮助我们处理海量的数据;在科学计算中,高精度计算可以提高计算的精度和可靠性。
高精度结构体:Bigint
这算是送给大家的一个礼物,是使用C++进行编写的结构体Bigint,集加、减、乘、除、输入、输出为一体。
#intclude<bits/stdc++.h>
struct Bigint {
std::vector<int> digits; // 存储每一位数字,低位在前
bool isNegative; // 标记是否为负数
Bigint() : isNegative(false) {}
// 构造函数,从字符串构造Bigint
Bigint(const std::string& str) : isNegative(false) {
if (str[0] == '-') {
isNegative = true;
for (size_t i = 1; i < str.length(); ++i) {
digits.push_back(str[i] - '0');
}
} else {
for (size_t i = 0; i < str.length(); ++i) {
digits.push_back(str[i] - '0');
}
}
std::reverse(digits.begin(), digits.end()); // 将数字反转,使得高位在后,方便计算
}
// 加法
Bigint operator+(const Bigint& b) const {
// 假设两个数都是正数,负数情况可以通过取反来处理
Bigint result;
int carry = 0;
size_t maxLength = std::max(digits.size(), b.digits.size());
for (size_t i = 0; i < maxLength || carry; ++i) {
int aDigit = i < digits.size() ? digits[i] : 0;
int bDigit = i < b.digits.size() ? b.digits[i] : 0;
int sum = aDigit + bDigit + carry;
carry = sum / 10;
result.digits.push_back(sum % 10);
}
while (result.digits.size() > 1 && result.digits.back() == 0) {
result.digits.pop_back(); // 去除前导零
}
return result;
}
// 减法(假设this >= b)
Bigint operator-(const Bigint& b) const {
Bigint result;
int borrow = 0;
for (size_t i = 0; i < digits.size(); ++i) {
int aDigit = digits[i];
int bDigit = i < b.digits.size() ? b.digits[i] : 0;
int diff = aDigit - bDigit - borrow;
if (diff < 0) {
diff += 10;
borrow = 1;
} else {
borrow = 0;
}
result.digits.push_back(diff);
}
while (result.digits.size() > 1 && result.digits.back() == 0) {
result.digits.pop_back(); // 去除前导零
}
return result;
}
// 乘法(简化版,未优化)
Bigint operator*(const Bigint& b) const {
Bigint result;
result.digits.resize(digits.size() + b.digits.size(), 0);
for (size_t i = 0; i < digits.size(); ++i) {
for (size_t j = 0; j < b.digits.size(); ++j) {
int product = digits[i] * b.digits[j];
result.digits[i + j] += product / 10; // 进位部分加到更高位上
result.digits[i + j + 1] += product % 10; // 个位数加到下一位上
}
}
for (size_t i = 0; i < result.digits.size() - 1; ++i) { // 处理进位
if (result.digits[i] >= 10) {
result.digits[i + 1] += result.digits[i] / 10;
result.digits[i] %= 10;
}
}
while (result.digits.size() > 1 && result.digits.back() == 0) {
result.digits.pop_back(); // 去除前导零
}
return result;
}
// 输入输出
friend std::istream& operator>>(std::istream& in, Bigint& b) {
std::string s;
in >> s;
b = Bigint(s);
return in;
}
friend std::ostream& operator<<(std::ostream& out, const Bigint& b) {
if (b.isNegative) out << '-';
for (auto it = b.digits.rbegin(); it != b.digits.rend(); ++it) {
out << *it;
}
return out;
}
};
// 示例使用
int main() {
Bigint a, b, sum, diff, prod;
std::cin >> a >> b;
sum = a + b;
diff = a - b; // 假设a >= b
prod = a * b;
std::cout << "Sum: " << sum << std::endl;
std::cout << "Difference: " << diff << std::endl;
std::cout << "Product: " << prod << std::endl;
return 0;
}
结语
高精度计算是编程领域的一个重要主题,它可以帮助我们解决标准数据类型无法处理的大数计算问题。在C++中,我们可以通过数组模拟或使用高精度库来实现高精度计算。随着技术的发展,高精度计算将在更多的领域得到应用,为我们的生活和工作带来更多的便利和可能性。
最后,我想说的是,高精度计算虽然有一定的难度,但只要我们掌握了基本的原理和方法,并多加练习和实践,就一定能够熟练掌握这一技能。希望这篇博客能够对大家有所帮助,让我们一起探索高精度计算的奥秘吧!
「C++」论高精度的更多相关文章
- 把虚拟教练带回家,「EuMotus」想用AI实现高精度运动反馈系统
https://36kr.com/p/5089139.html 无需穿戴设备,只需一个红外摄像头和+已安装好EuMotus专利软件的手提电脑 由政府主导的高达2200亿美金的健身与运动支出,15%的健 ...
- 「译」JUnit 5 系列:条件测试
原文地址:http://blog.codefx.org/libraries/junit-5-conditions/ 原文日期:08, May, 2016 译文首发:Linesh 的博客:「译」JUni ...
- 「译」JUnit 5 系列:扩展模型(Extension Model)
原文地址:http://blog.codefx.org/design/architecture/junit-5-extension-model/ 原文日期:11, Apr, 2016 译文首发:Lin ...
- JavaScript OOP 之「创建对象」
工厂模式 工厂模式是软件工程领域一种广为人知的设计模式,这种模式抽象了创建具体对象的过程.工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题. function createPers ...
- 「C++」理解智能指针
维基百科上面对于「智能指针」是这样描述的: 智能指针(英语:Smart pointer)是一种抽象的数据类型.在程序设计中,它通常是经由类型模板(class template)来实做,借由模板(tem ...
- 「JavaScript」四种跨域方式详解
超详细并且带 Demo 的 JavaScript 跨域指南来了! 本文基于你了解 JavaScript 的同源策略,并且了解使用跨域跨域的理由. 1. JSONP 首先要介绍的跨域方法必然是 JSON ...
- 「2014-5-31」Z-Stack - Modification of Zigbee Device Object for better network access management
写一份赏心悦目的工程文档,是很困难的事情.若想写得完善,不仅得用对工具(use the right tools),注重文笔,还得投入大把时间,真心是一件难度颇高的事情.但,若是真写好了,也是善莫大焉: ...
- 「2014-3-18」multi-pattern string match using aho-corasick
我是擅(倾)长(向)把一篇文章写成杂文的.毕竟,写博客记录生活点滴,比不得发 paper,要求字斟句酌八股结构到位:风格偏杂文一点,也是没人拒稿的.这么说来,arxiv 就好比是 paper 世界的博 ...
- 「2014-3-17」C pointer again …
记录一个比较基础的东东-- C 语言的指针,一直让人又爱又恨,爱它的人觉得它既灵活又强大,恨它的人觉得它太过于灵活太过于强大以至于容易将人绕晕.最早接触 C 语言,还是在刚进入大学的时候,算起来有好些 ...
- 「2014-3-13」Javascript Engine, Java VM, Python interpreter, PyPy – a glance
提要: url anchor (ajax) => javascript engine (1~4 articles) => java VM vs. python interpreter =& ...
随机推荐
- 前端使用 Konva 实现可视化设计器(5)
关于第三章提到的 selectingNodesArea,在后续的实现中已经精简掉了. 而 transformer 的 dragBoundFunc 中的逻辑,也直接移动 transformer 的 dr ...
- WIN11 安装 SQL Server 2019,SQLSERVER2022, MYSQL 8.0 ,Docker,Mongodb失败故障分析
最近研究数据库性能调优遇到各种数据库各种装不上,不知道熬了多少根软白沙,熬了多少颗张三疯,问了多少AI,查了多少网页,熬了两天,终于搞明白了一件事:那就是WIN11 ON ARM (因为拿的是MAC ...
- 如何基于香橙派AIpro对视频/图像数据进行预处理
本文分享自华为云社区<如何基于香橙派AIpro对视频/图像数据进行预处理>,作者: 昇腾CANN. 受网络结构和训练方式等因素的影响,绝大多数神经网络模型对输入数据都有格式上的限制.在计算 ...
- 如果千百年前有视觉AI算法,世界将会是什么样的光景呢?
视觉AI算法在近些年取得了一定的突破,被应用在了越来越多的地方,我相信距离真正的AI普及这个大目标也越来越近了.我时常在想假如古代也有视觉AI算法,那是不是很多故事的结局都将被改写?<伯乐相马& ...
- 利器解读!Linux 内核调测中最最让开发者头疼的 bug 有解了|龙蜥技术
简介:通过在Anolis 5.10 内核中增强 kfence 的功能,实现了一个线上的.精准的.可定制的内存调试解决方案. 编者按:一直持续存在内核内存调测领域两大行业难题: "内存被改& ...
- Linux系统诊断-内存基础
简介: Linux系统诊断-内存基础 1. 背景 谈及linux内存,很多时候,我们会关注free,top等基础命令.当系统遇到异常情况时,内存问题的根因追溯,现场诊断时,缺乏深层次的debug能力. ...
- [FAQ] 前端 点击事件或链接 如何打开两个外部窗口
点击链接支持 blank,但无法打开多个,考虑使用绑定 click 事件的方式. window.open 的采用需要有主动点击的情况,否则浏览器可能拦截. 如果是外部窗口,在点击时,优先使用 wind ...
- 从右边开始寻找整数的第k位
从右边开始寻找整数的第k位 Implement match_k, which takes in an integer k and returns a function that takes in a ...
- dotnet 在析构函数调用 ThreadLocal 也许会抛出对方已释放
我在不自量力做一个数组池,就是为了减少使用 System.Buffers.dll 程序集,然而在数组池里面,所用的 ThreadLocal 类型,在我对象析构函数进行归还数组时,抛出了无法访问已释放对 ...
- 构建RAG应用-day05: 如何评估 LLM 应用 评估并优化生成部分 评估并优化检索部分
评估 LLM 应用 1.一般评估思路 首先,你会在一到三个样本的小样本中调整 Prompt ,尝试使其在这些样本上起效. 随后,当你对系统进行进一步测试时,可能会遇到一些棘手的例子,这些例子无法通过 ...