Cpp 并行计算学习笔记
基本概念 首先学习几组基本概念: 并发(Concurrency)/并行(Parallelism) 同步(Synchronous)/异步(Asynchronous) 进程(Process)/线程(Thread) 并发 / 并行 并发指的是多个任务在同一时间段内被同时推进,可能是同时执行不同的任务,也可能是频繁交替执行每一个任务的一小部分 并行指的是多个任务在同一时间段内真正同时执行 举个例子: 学生在课后可以并发地完成每一个科目的作业:一会写语文作业,一会又切换回写数学作业,切换可以非常频繁,但是不可能同时写两科作业,也就是不能并行 人体的消化系统的任务和循环系统的任务在并行地执行:在同一时间内,肠道蠕动和血液循环在同时进行,不可能说心脏跳动时就让肠道蠕动暂停 同步 / 异步 同步是指任务按照顺序依次执行,每个任务在前一个任务完成后开始执行。在同步模式中,任务之间需要等待其他任务完成才能继续执行。 异步是指任务可以独立于其他任务进行执行,它们的执行过程不会产生堵塞。在异步模式中,任务可以在后台执行,执行结果可能需要等待一段时间才能获得,但这不会影响其他任务的执行。 ...
GCC 源码编译安装(离线,普通用户)
gcc 的非 root 用户离线编译安装比其他的软件的源码安装都要复杂:因为它有依赖,在服务器上无法通过联网下载,要提前下载依赖的压缩包,而且gcc的编译时间很长。 安装过程主要参考CentOS7 离线升级安装gcc到6.3.0 和Linux 非root安装GCC9.1.0 下载依赖 在官网或者镜像网站下载 gcc-11.4.0.tar.gz,传到服务器上解压为~/tmp/gcc-11.4.0 进入~/tmp/gcc-11.4.0子目录,需要解决下载依赖的问题。在可以联网的情况下,直接执行自带的下载依赖的脚本 ./contrib/download_prerequisites。如果服务器无法联网,则需要手动下载处理 查看上述脚本,找到四个必要的依赖 gmp,mpfr,mpc,isl 以及对应的具体版本,例如 gcc-11.4.0 需要的四个依赖版本及其下载地址如下(不同版本的gcc对应的依赖版本也不一样) 123456gmp='gmp-6.1.0.tar.bz2'mpfr='mpfr-3.1.6.tar.bz2'mpc='mpc-...
Cpp 面向对象——成员函数中的 this
整理一下关于C++类的成员函数所拥有的特殊的this指针的知识,并且学习C++23中的新内容:显式推导this。 隐式this 基础 this指针是C++面向对象编程中的重要机制,在自定义类型的非静态成员函数中,都存在这一个自动传递的this指针指向当前对象自身,例如 12345678910111213#include <iostream>struct Test { int data = 0; void call() { std::cout << "call: " << data << "\n"; }};int main() { Test test{1}; test.call(); return 0;} 对于编译器来说,这里的定义和调用过程等效于下面的形式(因为this是关键词,在代码中使用this_来代表) 1234567891011121314#include <iostre...
Cpp 未定义行为/小坑/冷知识
未定义行为 概述 C/C++存在很多的未定义行为,如果程序中使用了未定义行为,那么得到的结果是不可知的,编译器给出任何反馈都是符合语法标准的,因为未定义行为导致的BUG是难以察觉的。 未定义行为可能会导致编译报错,也可能导致运行出错等,还可能无事发生,具体结果可能与平台/编译器有关,不过在大部分情况下不同编译器会得到类似的结果。 未定义行为的存在是有客观原因的,一方面语法标准无法穷尽所有的可能情况;另一方面有些可能非法的行为(例如下标越界)在编译期难以直接检测,如果在运行期进行检测(例如检查下标越界),又会牺牲很多的运行效率。 如果我们在不经意间使用了未定义行为,那么即使是相同的代码,在C++的编译器不同等级的优化措施下,也可能得到完全不同的结果,例如: Debug模式正常,Release模式异常 例如产生随机的结果,通常的原因是使用没有正确初始化的变量,在Debug模式下被编译器初始化为0,但是Release模式下直接使用了内存中的随机值; 其它未定义行为,在Release模式下经过编译器优化中,产生不合理的结果。 Debug模式异常,Release模式正常 代码中的未...
编程语言中的整除和取余
整除和取余是两个看起来非常简单明确的基本数学运算,但是在不同编程语言的实现中,其实存在着很多的差异,需要注意一下。 数论中的整除和取余 我们从这两个概念的数学定义出发,在数论中的整除和取余定义为:对于整数 \(a,b \in \mathbb{Z}\),其中 \(b \neq 0\),存在唯一的商 \(q\in \mathbb{Z}\) 和余数 \(r \in \mathbb{Z}\),使得 \[ a = b \,q + r \] 对于余数要求 \(0 \le r < b\),即余数是一个非负的且不超过除数的整数。 虽然初等数论主要关注的都是整数,通常不会涉及对实数的整除和取余运算,但是我们仍然可以直接将上述定义推广到实数中:对于实数 \(a,b \in \mathbb{R}\),其中 \(b \neq 0\),存在唯一的商 \(q\in \mathbb{Z}\) 和余数 \(r \in \mathbb{R}\),使得 \[ a = b \,q + r \] 对于余数要求 \(0 \le r < b\),即余数是一个非负的且不超过除数的实数。 数论中要求在任何情况下,...
关于编程语言的理解
不再细究某个编程语言的细节,而是从宏观角度来理解编程语言的设计哲学。 部分内容取自网络资料和GPT,仅作为学习整理,不保证正确性,事实上这部分内容在网上的中文资料很混乱,有很多都是错的。 编程范式的历史与演变 简单回顾一下编程范式的历史与演变。 顺序编程 在早期编程中,人们采用的编程方式被称为顺序编程(非结构化编程)——程序按照上下文顺序执行指令,GOTO语句在其中发挥了重要作用, 它可以无条件地跳转到程序的任意部分。 GOTO语句的滥用导致了“意大利面条式代码”,使得程序变得难以理解和维护。为了克服GOTO语句带来的代码混乱,20世纪60年代Edsger Dijkstra等人提出了结构化编程。 结构化编程 结构化编程的核心是控制结构,例如顺序、选择(如if、switch)、循环(如for、while)等结构,通过这些控制结构来组织代码,尽可能避免GOTO语句的使用。控制结构提高了代码的可读性和维护性,是现代编程语言的重要基础。 面向过程编程 面向过程编程是基于函数调用的编程范式,通过一系列过程(函数)的调用来组织代码,C语言是其中的典型代表。 面向过程编程的特点是数据与操作...
编程语言中的整数和浮点数
整理一下编程语言中的整数和浮点数的相关内容,针对的情景是科学计算。 整数 整数模型 编程语言中的整数类型不同于数学意义上的整数,而只是它的一个有限子集,因为计算机为了计算效率,会使用固定的字节数来存储一个整数数据,例如 \(n\) 个字节,这意味这只有 \(2^{8n}\) 个不同状态,只能表示 \(2^{8n}\) 个整数。 将 \(n\) 个字节所对应的 \(8n\) 比特的值依次记作 \(a_i \in \{0,1\}\),这里 \(i=0,\dots,8n-1\),那么通常有两类方案: 第一种方案是无符号整数,表示的值 \(V\) 为 \[ V = 2^0 a_0 + 2^1 a_1 + \dots + 2^{8n-2} a_{8n-2} + 2^{8n-1} a_{8n-1} \] 表示的范围为 \[ [0,2^{8n}-1] \] 第二种方案是有符号整数,表示的值 \(V\) 为 \[ V = 2^0 a_0 + 2^1 a_1 + \dots + 2^{8n-2} a_{8n-2} - 2^{8n-1} a_{8n-1} \] 表示的范围为 \[ [-2^{8n-1...
C语言 weak弱符号(GCC扩展)
__attribute__((weak)) 是 GCC 和 Clang 提供的一个特性,用于声明一个符号为 "弱符号"(weak symbol),在链接层面提供更多的灵活性。注意并不是 C 语言标准的一部分,MSVC并不支持,但是提供了一个类似的特性:#pragma weak。 概述 编译器将一个符号(函数名,变量名)区分为强符号(strong symbol)和弱符号(weak symbol),通常绝大多数的符号都是强符号,重复出现会导致链接错误。在定义时使用 __attribute__((weak)) 可以将其设置为弱符号,语法如下(在符号声明时不需要) 1<符号类型> __attribute__((weak)) <符号名称>; 这可以使得它在链接过程中具有较低的优先级: 如果在链接过程中找到了同名的强符号和弱符号,弱符号会被强符号覆盖。 如果找到多个同名的强符号,会导致链接错误(link error)。 在没有找到强符号时:如果只有唯一的弱符号,那么这个弱符号会被使用;如果存在多个同名的弱符号,可能会使用其中一个版本,取决于具体实现,并且很可能和链接...
时间离散的潜在问题
在数值求解PDE时,通常需要分别进行时空离散: 空间离散比较复杂:与具体格式相关,涉及到网格剖分与加密,单元之间的数据交换,边界处理等; 时间离散比较简单:只需要加上一层for或者while循环,最多加上时间步长的自适应调整即可。 但是看起来非常简单的时间离散,在具体编程中也可能存在一些潜在的问题,下面用几个例子说明。 例一 考虑下面的时间离散 123456t = 0.0while t < T: dt = get_dt(data) update(data, t, dt) t += dt 这段代码的问题比较明显:最后一个时间迭代可能越界,出现 \(t + \Delta t > T\) 的情况。 加上越界判断即可 123456789t = 0.0while t < T: dt = get_dt(data) if t + dt >= T: dt = T - t update(data, t, dt) t += dt 例二 一个不易察觉的事实是:浮点数的累加是存在误差的,这在一些情况下会导致最后一个时间步...
Zotero 7 配置笔记
磨刀不误砍柴工,文献管理软件这把刀确实是值得打磨的,选择Zotero而非其它文献管理工具,主要是看重了它的免费和可配置性,适合重度使用。 最新版 Zotero 7 在 Zotero 6 的基础上,进行了升级,包括非常多的优化,例如最基础的UI看着更漂亮了,等我把它的各种插件和配置都鼓捣好了,就更有动力(但愿吧)打开来看文献了。 网上关于Zotero有很多分享教程,但是绝大部分都是入门级的配置笔记,参考价值并不大,本文最主要的参考是Zotero非官方中文社区。 基础 本地安装 直接从官网下载 Zotero 7,然后傻瓜式安装即可,需要注意的是两个位置: 首先是软件安装位置,可以使用自定义安装方式,挑一个合适的位置即可,例如D:\ProgramMain\Zotero7; 然后是本地数据存储位置,默认是~/Zotero。 数据存储位置比较占地方,我想将其迁移到别的位置,例如E:\<user>\Documents\Zotero7,首先需要在设置中更改 1编辑 -> 设置 -> 高级 -> 数据存储位置 将其更改为自定义的目标路径,然后根据提示进行操作:将...