活动介绍

C++并发编程与数值函数实用指南

立即解锁
发布时间: 2025-08-22 00:43:55 阅读量: 3 订阅数: 16
PDF

深入解析C++标准库:从入门到精通

### C++ 并发编程与数值函数实用指南 #### 1. 全局数值函数 在 C++ 里,`<cmath>` 和 `<cstdlib>` 头文件提供了从 C 语言继承而来的全局数值函数。这些函数能满足各种数值计算需求,下面是它们的详细介绍。 ##### 1.1 `<cmath>` 头文件中的函数 | 函数 | 作用 | | --- | --- | | `pow()` | 幂函数 | | `exp()` | 指数函数 | | `sqrt()` | 平方根函数 | | `log()` | 自然对数函数 | | `log10()` | 以 10 为底的对数函数 | | `sin()` | 正弦函数 | | `cos()` | 余弦函数 | | `tan()` | 正切函数 | | `sinh()` | 双曲正弦函数 | | `cosh()` | 双曲余弦函数 | | `tanh()` | 双曲正切函数 | | `asin()` | 反正弦函数 | | `acos()` | 反余弦函数 | | `atan()` | 反正切函数 | | `atan2()` | 商的反正切函数 | | `asinh()` | 反双曲正弦函数(C++11 起) | | `acosh()` | 反双曲余弦函数(C++11 起) | | `atanh()` | 反双曲正切函数(C++11 起) | | `ceil()` | 将浮点值向上舍入为下一个整数值 | | `floor()` | 将浮点值向下舍入为下一个整数值 | | `fabs()` | 浮点值的绝对值 | | `fmod()` | 浮点值除法的余数(取模) | | `frexp()` | 将浮点值转换为小数和整数部分 | | `ldexp()` | 将浮点值乘以 2 的整数次幂 | | `modf()` | 从浮点值中提取有符号整数和小数部分 | 与 C 语言不同,C++ 对部分操作进行了不同类型的重载,这使得 C 语言里的一些数值函数变得多余。例如,在 C 语言中,处理不同类型的绝对值需要使用 `abs()`、`labs()`、`llabs()`、`fabs()`、`fabsf()` 和 `fabsl()` 等函数,而在 C++ 里,`abs()` 函数被重载,可用于所有这些数据类型。 ##### 1.2 `<cstdlib>` 头文件中的数值函数 | 函数 | 作用 | | --- | --- | | `abs()` | 整数的绝对值 | | `labs()` | 长整数的绝对值 | | `llabs()` | 长长整数的绝对值(C++11 起) | | `div()` | 整数除法的商和余数 | | `ldiv()` | 长整数除法的商和余数 | | `lldiv()` | 长长整数除法的商和余数(C++11 起) | | `srand()` | 随机值生成器(设置新序列的种子) | | `rand()` | 随机值生成器(生成序列中的下一个数) | 所有用于整数的数值函数都针对 `int`、`long` 和 `long long` 类型进行了重载,而所有用于浮点值的数值函数则针对 `float`、`double` 和 `long double` 类型进行了重载。不过,这会带来一个问题:当你传递一个整数值,而只有多个浮点重载存在时,表达式会产生歧义。例如: ```cpp std::sqrt(7) // 有歧义: sqrt(float), sqrt(double), 还是 sqrt(long double)? ``` 为避免这种情况,你需要这样写: ```cpp std::sqrt(7.0) // 正确 ``` 或者,如果你使用变量,必须写成: ```cpp int x; // ... std::sqrt(float(x)) // 正确 ``` 不同的库供应商对这个问题的处理方式各不相同。为编写可移植的代码,你应该始终确保代码中的参数精确匹配。 #### 2. Valarrays 自 C++98 起,C++ 标准库就提供了 `valarray` 类,用于处理数值数组。 ##### 2.1 Valarrays 的用途 `valarray` 是数学概念中值的线性序列的一种表示。它是一维的,但通过特殊的计算索引技术和强大的子集选取功能,你可以获得更高维度的错觉。因此,`valarray` 可作为向量和矩阵运算的基础,也可用于处理多项式方程组的数学系统,且性能良好。 从技术上讲,`valarray` 是一维数组,元素从 0 开始顺序编号。它能对一个或多个值数组中的所有或部分值进行数值处理。例如,你可以处理如下语句: ```cpp z = a*x*x + b*x + c ``` 其中 `a`、`b`、`c`、`x` 和 `z` 是包含数百个数值的数组。这样做的好处是表示简单。而且,处理性能也不错,因为这些类提供了一些优化,避免在处理整个语句时创建临时对象。这是因为 `valarray` 保证无别名,即非常量 `valarray` 的任何值都通过唯一路径访问,编译器在优化操作时无需考虑数据可能通过其他路径访问的情况。 此外,特殊的接口和辅助类提供了处理值数组特定子集或进行多维处理的能力,有助于实现向量和矩阵运算及相关类。 ##### 2.2 Valarrays 的问题 `valarray` 类的设计并不理想。实际上,没人去验证最终规范是否可行,这是因为没人对这些类负责。将 `valarray` 引入 C++ 标准库的人在标准完成前很久就离开了委员会,导致 `valarray` 很少被使用。 #### 3. 并发编程基础 现代系统架构通常支持同时运行多个任务和线程。特别是在有多个处理器核心的情况下,使用多线程能显著提高程序的执行时间。然而,并行执行也会带来新的挑战,比如多个线程同时访问相同资源,可能导致创建、读取、写入和删除操作无法按预期顺序进行,从而产生意外结果。在 C++11 之前,语言和标准库都不支持并发编程,不过实现可以自行提供一些保证。C++11 改变了这一状况,核心语言和库都得到改进以支持并发编程。 核心语言定义了一个内存模型,确保两个不同线程使用的两个不同对象的更新相互独立,并引入了新关键字 `thread_local` 来定义具有线程特定值的变量。标准库提供了启动多个线程的支持,包括跨线程边界传递参数、返回值和异常,以及同步多个线程的方法,从而实现控制流和数据访问的同步。 #### 4. 高级接口:`async()` 和 `Futures` 对于初学者来说,使用 C++ 标准库的高级接口 `std::async()` 和 `std::future<>` 是开启多线程编程的最佳起点。 ##### 4.1 `async()` 和 `Futures` 的第一个示例 假设要计算两个函数调用返回的操作数之和,通常的编程方式是: ```cpp func1() + func2() ``` 这种方式下,操作数的处理是顺序进行的,程序会先调用 `func1()`,再调用 `func2()`,或者反之,整体处理时间是 `func1()` 的执行时间加上 `func2()` 的执行时间再加上计算和的时间。 现在,借助几乎随处可见的多处理器硬件,我们可以尝试并行运行 `func1()` 和 `func2()`,这样整体时间只需 `func1()` 和 `func2()` 执行时间的最大值加上计算和的时间。以下是实现该功能的示例代码: ```cpp // concurrency/async1.cpp #include <future> #include <thread> #include <chrono> #include <random> #include <iostream> #include <exception> using namespace std; int doSomething (char c) { // 随机数生成器 (使用 c 作为种子以获得不同序列) std::default_random_engine dre(c); std::uniform_int_distribution<int> id(10,1000); // 循环在随机时间段后打印字符 for (int i=0; i<10; ++i) { this_thread::sleep_for(chrono::milliseconds(id(dre))); cout.put(c).flush(); } return c; } int func1 () { return doSomething('.'); } int func2 () { return doSomething('+'); } int main() { std::cout << "starting func1() in background" << " and func2() in foreground:" << std::endl; // 异步启动 func1() (现在、稍后或不启动): std::future<int> result1(std::async(func1)); int result2 = func2(); // 同步调用 func2() // 打印结果 (等待 func1() 完成并将其结果与 result2 相加) int result = result1.get() + result2; std::cout << "\nresult of func1()+func2(): " << result << std::endl; } ``` 这里,我们通过调用 `doSomething()` 函数模拟 `func1()` 和 `func2()` 中的复杂处理,该函数会不时打印传入的字符,并最终返回该字符的整数值。“不时” 是通过随机数生成器指定间隔实现的,`std::this_thread::sleep_for()` 会使用这些间隔作为当前线程的超时时间。 我们没有直接调用 `int result = func1() + func2();`,而是按如下方式调用: ```cpp std::future<int> result1(std::async(func1)); int result2 = func2(); int result = result1.get() + result2; ``` 首先,使用 `std::async()` 尝试在后台启动 `func1()`,并将结果赋值给 `std::future` 对象。`async()` 会尝试在单独的线程中异步立即启动传入的功能,理想情况下,`func1()` 会在此处启动,而不会阻塞 `main()` 函数。返回的 `future` 对象有两个重要作用: 1. 它允许访问传递给 `async()` 的功能的 “未来” 结果,这个结果可能是返回值或异常。`future` 对象根据启动的功能的返回类型进行了特化,如果启动的后台任务没有返回值,则应为 `std::future<void>`。 2. 它确保传入的功能迟早会被调用。如果 `async()` 未能立即启动该功能,当我们需要结果或确保功能已执行时,`future` 对象会强制启动该功能。 接着,在前台同步调用 `func2()`,如果 `func1()` 成功启动且尚未结束,此时 `func1()` 和 `func2()` 会并行运行。最后,调用 `result1.get()` 获取 `func1()` 的结果并与 `result2` 相加。调用 `get()` 时,可能会出现以下三种情况: 1. 如果 `func1()` 在单独的线程中启动且已完成,会立即得到其结果。 2. 如果 `func1()` 已启动但尚未完成,`get()` 会阻塞并等待其结束,然后返回结果。 3. 如果 `func1()` 尚未启动,它将被强制启动,并且 `get()` 会像同步函数调用一样阻塞,直到返回结果。 这种行为确保了程序在单线程环境或因其他原因 `async()` 无法启动新线程的情况下仍能正常工作。`async()` 调用并不保证传入的功能一定会启动并完成,如果有线程可用,它会启动;否则,调用会被推迟,直到我们显式请求其结果(调用 `get()`)或希望该功能完成(调用 `wait()`)。 因此,`std::future<int> result1(std::async(func1));` 和 `result1.get()` 的组合能优化程序,使 `func1()` 尽可能与主线程中的后续语句并行运行。如果无法并行运行,在调用 `get()` 时会顺序调用 `func1()`。 根据这个示例,我们可以总结出让程序更快的通用方法: 1. 包含 `<future>` 头文件。 2. 将可以独立并行运行的功能作为可调用对象传递给 `std::async()`。 3. 将结果赋值给 `future<ReturnType>` 对象。 4. 当需要结果或确保启动的功能已完成时,调用 `future<>` 对象的 `get()` 方法。 需要注意的是,这仅适用于没有数据竞争的情况,即两个线程同时使用相同数据会导致未定义行为。而且,不调用 `get()` 就无法保证 `func1()` 会被调用。另外,要确保在必要时才请求 `async()` 启动的功能的结果,否则可能会导致顺序处理。一般来说,目标是最大化调用 `async()` 和调用 `get()` 之间的时间间隔。 如果传递给 `async()` 的操作没有返回值,`async()` 会返回 `future<void>`,此时 `get()` 不返回任何值。最后,传递给 `async()` 的对象可以是任何类型的可调用对象,如函数、成员函数、函数对象或 lambda 表达式。 ##### 4.2 使用启动策略 你可以通过显式传递启动策略来强制 `async()` 不推迟传入的功能。例如: ```cpp // 强制 func1() 立即异步启动,否则抛出 std::system_error std::future<long> result1 = std::async(std::launch::async, func1); ``` 如果无法进行异步调用,程序会抛出 `std::system_error` 异常,错误代码为 `resource_un
corwn 最低0.47元/天 解锁专栏
赠100次下载
继续阅读 点击查看下一篇
profit 400次 会员资源下载次数
profit 300万+ 优质博客文章
profit 1000万+ 优质下载资源
profit 1000万+ 优质文库回答
复制全文

相关推荐

SW_孙维

开发技术专家
知名科技公司工程师,开发技术领域拥有丰富的工作经验和专业知识。曾负责设计和开发多个复杂的软件系统,涉及到大规模数据处理、分布式系统和高性能计算等方面。
最低0.47元/天 解锁专栏
赠100次下载
百万级 高质量VIP文章无限畅学
千万级 优质资源任意下载
千万级 优质文库回答免费看
立即解锁

专栏目录

最新推荐

【MATLAB词性标注统计分析】:数据探索与可视化秘籍

![【MATLAB词性标注统计分析】:数据探索与可视化秘籍](https://img-blog.csdnimg.cn/097532888a7d489e8b2423b88116c503.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzMzNjI4MQ==,size_16,color_FFFFFF,t_70) # 摘要 MATLAB作为一种强大的数学计算和可视化工具,其在词性标注和数据分析领域的应用越来越广泛。本文

高斯过程可视化:直观理解模型预测与不确定性分析

# 摘要 高斯过程(Gaussian Processes, GP)是一种强大的非参数贝叶斯模型,在机器学习和时间序列分析等领域有着广泛应用。本文系统地介绍了高斯过程的基本概念、数学原理、实现方法、可视化技术及应用实例分析。文章首先阐述了高斯过程的定义、性质和数学推导,然后详细说明了高斯过程训练过程中的关键步骤和预测机制,以及如何进行超参数调优。接着,本文探讨了高斯过程的可视化技术,包括展示预测结果的直观解释以及多维数据和不确定性的图形化展示。最后,本文分析了高斯过程在时间序列预测和机器学习中的具体应用,并展望了高斯过程未来的发展趋势和面临的挑战。本文旨在为高斯过程的学习者和研究者提供一份全面的

自动化脚本编写:简化you-get下载流程的秘诀

![自动化脚本编写:简化you-get下载流程的秘诀](https://www.edureka.co/blog/content/ver.1531719070/uploads/2018/07/CI-CD-Pipeline-Hands-on-CI-CD-Pipeline-edureka-5.png) # 摘要 随着数字内容的爆炸性增长,自动化脚本在内容管理和数据处理中的作用变得越来越重要。本文首先介绍了自动化脚本编写的基础知识,并以you-get工具作为实践案例,详细阐述了其基础应用与脚本化过程。随后,文章进一步深入探讨了自动化脚本的高级定制方法,包括参数化、高级下载功能实现以及维护与扩展性的策

【FPGA信号完整性故障排除】:Zynq7045-2FFG900挑战与解决方案指南

![【FPGA信号完整性故障排除】:Zynq7045-2FFG900挑战与解决方案指南](https://www.protoexpress.com/wp-content/uploads/2024/04/Parallel-termination-_diff.-pair-1-1024x421.jpg) # 摘要 随着电子系统对性能要求的日益提高,FPGA信号完整性成为设计和实现高性能电子系统的关键。本文从FPGA信号完整性基础讲起,分析了Zynq7045-2FFG900在高速接口设计中面临的信号完整性挑战,包括信号反射、串扰、电源地线完整性和热效应等问题,并探讨了硬件设计因素如PCB布局和元件选

FUNGuild与微生物群落功能研究:深入探索与应用

![FUNGuild与微生物群落功能研究:深入探索与应用](https://d3i71xaburhd42.cloudfront.net/91e6c08983f498bb10642437db68ae798a37dbe1/5-Figure1-1.png) # 摘要 FUNGuild作为一个先进的微生物群落功能分类工具,已在多个领域展示了其在分析和解释微生物数据方面的强大能力。本文介绍了FUNGuild的理论基础及其在微生物群落分析中的应用,涉及从数据获取、预处理到功能群鉴定及分类的全流程。同时,本文探讨了FUNGuild在不同环境(土壤、水体、人体)研究中的案例研究,以及其在科研和工业领域中的创

【进阶知识掌握】:MATLAB图像处理中的相位一致性技术精通

![相位一致性](https://connecthostproject.com/images/8psk_table_diag.png) # 摘要 MATLAB作为一种高效的图像处理工具,其在相位一致性技术实现方面发挥着重要作用。本文首先介绍MATLAB在图像处理中的基础应用,随后深入探讨相位一致性的理论基础,包括信号分析、定义、计算原理及其在视觉感知和计算机视觉任务中的应用。第三章重点阐述了如何在MATLAB中实现相位一致性算法,并提供了算法编写、调试和验证的实际操作指南。第四章对算法性能进行优化,并探讨相位一致性技术的扩展应用。最后,通过案例分析与实操经验分享,展示了相位一致性技术在实际图

【VB.NET GUI设计】:WinForms与WPF设计与实现的艺术

![【VB.NET GUI设计】:WinForms与WPF设计与实现的艺术](https://www.der-wirtschaftsingenieur.de/bilder/it/visual-studio-c-sharp.png) # 摘要 本文系统地介绍了VB.NET环境下的图形用户界面(GUI)设计,重点讲解了WinForms和WPF两种技术的使用与进阶。首先,概述了VB.NET在GUI设计中的作用,并对WinForms设计的基础进行了深入探讨,包括事件驱动编程模型、表单和控件的运用、界面布局技巧以及数据绑定和事件处理。随后,转向WPF设计的进阶知识,强调了M-V-VM模式、XAML语法

【HCIA-Datacom无线网络部署】:打造稳定高效无线环境的秘籍

![【HCIA-Datacom无线网络部署】:打造稳定高效无线环境的秘籍](https://blog.albentia.com/wp-content/uploads/2013/09/propagacic3b3n-multitrayecto.png) # 摘要 随着无线技术的快速发展和广泛应用,无线网络已成为现代社会信息传输的重要组成部分。本文全面概述了无线网络的基础知识,深入探讨了无线网络设备和标准,包括接入点、网卡以及安全协议。此外,文章还详细介绍了无线网络的部署实践,包括规划、配置、性能调优与故障排查。针对网络安全问题,本文提出了加固策略,并探讨了高密度部署、物联网接入和无线网络虚拟化等

【CAD转UDEC:全面优化指南】:提升转换效率与模型质量

# 摘要 随着计算机辅助设计(CAD)在工程分析中的广泛应用,将CAD模型高效准确地转换为离散元分析(UDEC)模型已成为岩土工程研究的重要环节。本文首先介绍了CAD模型转UDEC的理论基础与优化方法,强调了CAD模型质量对转换效果的重要性,并探讨了几何简化、材料属性和网格质量控制的优化理论。接着,本文详细阐述了转换操作的实践步骤,包括软件选择、参数设置、模型预处理以及转换过程中的质量检查。文章还讨论了UDEC模型的后处理与分析,包括模型验证、数值模拟、性能提升策略以及常见问题的解决。最后,通过高级应用案例,展示了复杂地形模型转换的实例分析和CAD转UDEC在实际工程项目中的应用效果评估。

数据隐私与合规性问题:数据库需求分析中的【关键考量】

![数据隐私与合规性问题:数据库需求分析中的【关键考量】](https://www.collidu.com/media/catalog/product/img/f/8/f834a9dd19e7431b1ebd7219f776ee0921f7540df717b7b86435cb800f48607b/gdpr-compliance-slide1.png) # 摘要 随着信息技术的快速发展,数据隐私与合规性问题日益突出,成为数据库设计和管理的重要议题。本文从数据隐私与合规性概述出发,深入探讨了数据库设计中的隐私保护策略,包括数据分类、敏感度评估、数据加密与匿名化技术以及访问控制与权限管理等。此外,