多线程之基于积分法与欧拉恒等式法的圆周率计算及OMP优化

2023-05-16

文章目录

    • 一、问题描述
    • 二、积分法
      • 算法推导
      • 编程实现
      • OMP优化
    • 三、欧拉恒等式
      • 算法推导
      • 编程实现
        • 前期准备
          • 加法
          • 减法
          • 乘法
          • 除法
        • 算法实现
      • OMP优化
    • 四、总结
      • 积分法与欧拉恒等式法的对比
      • OMP实现方式的对比

一、问题描述

  • 分别采用积分法和欧拉恒等式计算π,对比两种方法

  • 使用OMP实现以上两种方法,再进行对比

二、积分法

算法推导

首先我们知道 a r c t a n ( x ) arctan(x) arctan(x)的导数 f ′ ( x ) = 1 1 + t 2 f'(x)=\frac{1}{1+t^2} f(x)=1+t21,所以有:
a r c t a n ( x ) = ∫ 0 x 1 1 + t 2 d t (1) arctan(x)=\int_0^x\frac{1}{1+t^2}dt\tag{1} arctan(x)=0x1+t21dt(1)
x = 1 x=1 x=1得到
π 4 = a r c t a n ( 1 ) = ∫ 0 1 1 1 + t 2 d t (2) \frac{π}{4}=arctan(1)=\int_0^1\frac{1}{1+t^2}dt\tag{2} 4π=arctan(1)=011+t21dt(2)
离散化后得到
π = ∑ n = 0 N 4 Δ t 1 + ( n Δ t ) 2 , Δ t = 1 N , N → + ∞ (3) π=\sum_{n=0}^N\frac{4\varDelta t}{1+(n\varDelta t)^2},\varDelta t=\frac{1}{N},N\to +\infty\tag{3} π=n=0N1+(nΔt)24Δt,Δt=N1,N+(3)

编程实现

这种方法的计算速度比较慢,计算结果的最小位数与 Δ t \varDelta t Δt成线性关系,所以一般不用于计算高精度π。如果不追求高精度的话,用C++实现式(3)难度不大。

#include <cstdio>
#include <ctime>
#include <cmath>
using namespace std;

int main(void)
{
	clock_t startTime = clock();

	const long long N = 1e9;
	double deltaT = 1 / (N * 1.0);
	double sum = 0;

	for (long long i = 0; i < N; i++){
		double x = i * deltaT;
		sum += 4 / (1 + x * x) * deltaT;
	}
	printf("%.12lf\n", sum);
	printf("The run time is: %.3fs\n", (clock() - (int)startTime) / 1000.0);
}

运行结果:
在这里插入图片描述

OMP优化

首先添加头文件*<omp.h>*,在for循环前添加

#pragma omp parallel for reduction(+:sum)

reduction(+:sum)即为变量sum指定一个操作符+,每个线程都会创建变量sum的私有拷贝,在OMP区域结束后将使用各个线程的私有拷贝的值通过指定的操作符进行迭代运算,并赋值给原来的变量sum

运行结果为:
在这里插入图片描述

一段程序可由 3 部分组成:准备(setup)、计算 (compute)和结束(finalization) 部分,当计算量足够大时,可以忽略准备和结束部分所占用的时间,所以以下指标的计算只针对计算部分:

相对加速比:
S ( P ) = 4.871 1.424 ≈ 3.461 S(P)=\frac{4.871}{1.424}≈3.461 S(P)=1.4244.8713.461
并行化效率:
E i n t e = S ( P ) 8 ≈ 0.428 E_{inte}=\frac{S(P)}{8}≈0.428 Einte=8S(P)0.428

三、欧拉恒等式

接下来使用欧拉恒等式实现高精度π的计算

算法推导

欧拉恒等式被认为是数学上最优美的公式之一,它将自然常数 e e e,圆周率 π π π,虚数单位 i i i,自然数 1 , 0 1,0 1,0这五个最基本的数字连接在一起:
e i π + 1 = 0 (1) e^{iπ}+1=0\tag{1} eiπ+1=0(1)
我们可以由它计算出π,由该式容易得到
π = l n ( − 1 ) i = 2 i l n i (2) π=\frac{ln(-1)}{i}=\frac{2}{i}lni\tag{2} π=iln(1)=i2lni(2)
再由虚数的性质可以得到
l n i = l n 1 + i 1 − i = l n ( 1 + i ) − l n ( 1 − i ) (3) lni=ln\frac{1+i}{1-i}=ln(1+i)-ln(1-i)\tag{3} lni=ln1i1+i=ln(1+i)ln(1i)(3)
首先对 l n ( 1 + x ) ln(1+x) ln(1+x)做泰勒级数展开,有:
l n ( 1 + x ) = x − 1 2 x 2 + 1 3 x 3 − 1 4 x 4 + 1 5 x 5 − … … (4) ln(1+x)=x-\frac{1}{2}x^2+\frac{1}{3}x^3-\frac{1}{4}x^4+\frac{1}{5}x^5-\dots\dots\tag{4} ln(1+x)=x21x2+31x341x4+51x5(4)
x = ± i x=±i x=±i,得:
l n ( 1 + i ) = i + 1 2 − 1 3 i − 1 4 + 1 5 i + … … (5) ln(1+i)=i+\frac{1}{2}-\frac{1}{3}i-\frac{1}{4}+\frac{1}{5}i+\dots\dots\tag{5} ln(1+i)=i+2131i41+51i+(5)

l n ( 1 − i ) = − i + 1 2 + 1 3 i − 1 4 − 1 5 i + … … (6) ln(1-i)=-i+\frac{1}{2}+\frac{1}{3}i-\frac{1}{4}-\frac{1}{5}i+\dots\dots\tag{6} ln(1i)=i+21+31i4151i+(6)

由上式得到
π 4 = 1 − 1 3 + 1 5 − … … (7) \frac{π}{4}=1-\frac{1}{3}+\frac{1}{5}-\dots\dots\tag{7} 4π=131+51(7)
这个公式是莱布尼茨级数,但是用其来求圆周率π的效率过低,迭代10万次才能精确到小数点后六位。所以继续变换 l n i lni lni
KaTeX parse error: No such environment: equation at position 8: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲ lni=ln\frac{(2…
最后可以得到如下计算圆周率的公式:
π 4 = ( 1 2 + 1 3 ) − 1 3 ( 1 2 3 + 1 3 3 ) + 1 5 ( 1 2 5 + 1 3 5 ) − … … (9) \frac{π}{4}=(\frac{1}{2}+\frac{1}{3})-\frac{1}{3}(\frac{1}{2^3}+\frac{1}{3^3})+\frac{1}{5}(\frac{1}{2^5}+\frac{1}{3^5})-\dots\dots\tag{9} 4π=(21+31)31(231+331)+51(251+351)(9)
用这个公式只需要取前4项就可以达到祖冲之的效果。当然还可以推出其他效率更高的公式,但是以下的程序都以这个公式为框架。

编程实现

前期准备

为了实现高精度π的计算,我们使用数组来存储π,所以对应地需要实现数组间的加减乘除操作

  • 加法
/**
 * @brief 实现两个数组的加法
 * @param b			加数1,以及结果保存数组
 * @param a			加数2
 * @param n			结果位数
 * @return none
 */
void calc_add(int b[], int a[], int n)
{
	int carry = 0;
	for (int i = n - 1; i >= 0; i--)
	{
		b[i] = a[i] + b[i] + carry;
		carry = b[i] / 10;
		b[i] %= 10;
	}
}
  • 减法
/**
 * @brief 实现两个数组的减法
 * @param b			被减数,以及结果保存数组
 * @param a			减数
 * @param n			结果位数
 * @return none
 */
void calc_sub(int b[], int a[], int n)
{
	int carry = 0;
	for (int i = n - 1; i >= 0; i--)
	{
		b[i] = b[i] - a[i] - carry;
		carry = b[i] < 0;
		b[i] = carry ? (10 + b[i]) : b[i];
	}
}
  • 乘法
/**
 * @brief 实现两个数组的乘法
 * @param a			乘数1,以及结果保存数组
 * @param b			乘数2
 * @param n			结果位数
 * @return none
 */
void calc_multi(int a[], int b[], int n)
{
	int* result = new int[2 * n]{ 0 };
	for (int i = 0; i < n; i++)
	{
		int* c = new int[2 * n]{ 0 };
		for (int j = 0; j < n; j++)
		{
			c[i + j] = a[i] * b[j];
		}
		calc_add(result, c, n + n / 10);
		delete[] c;
	}
	for (int i = 0; i < n; i++)
	{
		a[i] = result[i];
	}
	delete[] result;
}

  • 除法

除法操作与其他操作有所不同,只用一个数组来保存结果,并且限制分母范围为 ( − 2 31 , 2 31 − 1 ) (-2^{31},2^{31}-1) (231,2311)

/**
 * @brief 用数组存储两个整型数据相除结果
 * @param result[]	结果保存数组
 * @param y			被除数
 * @param x			除数
 * @param n			结果位数
 * @return none
 */
void calc_div(int result[], int y, int x, int n)
{
	for (int i = 0; i < n; i++)
	{
		result[i] = y / x;
		y = y % x;
		y *= 10;
	}
}

算法实现

根据式(9)写出π的计算通式:
π = ∑ i = 1 N ( − 1 ) i − 1 4 2 i − 1 ( 1 2 2 i − 1 + 1 3 2 i − 1 ) , N → + ∞ (10) π=\sum_{i=1}^N(-1)^{i-1}\frac{4}{2i-1}(\frac{1}{2^{2i-1}}+\frac{1}{3^{2i-1}}),N\to +\infty\tag{10} π=i=1N(1)i12i14(22i11+32i11),N+(10)

y k = ( − 1 ) k − 1 4 2 k − 1 ( 1 2 2 k − 1 + 1 3 2 k − 1 ) , k ∈ Z + (11) y_k=(-1)^{k-1}\frac{4}{2k-1}(\frac{1}{2^{2k-1}}+\frac{1}{3^{2k-1}}),k\in Z^+\tag{11} yk=(1)k12k14(22k11+32k11),kZ+(11)

π = ∑ k = 1 N y k (12) π=\sum_{k=1}^Ny_k\tag{12} π=k=1Nyk(12)
我们可以对式(11)进行拆分,令 { a k = 4 2 k − 1 b k = 1 2 2 k − 1 + 1 3 2 k − 1 \begin{cases}a_k=\frac{4}{2k-1} \\b_k=\frac{1}{2^{2k-1}}+\frac{1}{3^{2k-1}}\end{cases} {ak=2k14bk=22k11+32k11,则:
y k = ( − 1 ) k − 1 a k b k (13) y_k=(-1)^{k-1}a_kb_k\tag{13} yk=(1)k1akbk(13)
因此可以分别计算 a k , b k a_k,b_k ak,bk,然后将两项的结果相乘得到 y k y_k yk,再对 y k y_k yk求和得到π

观察 a k , b k a_k,b_k ak,bk,发现 b k b_k bk的分母呈指数级增长形势,当计算 { y k } \begin{Bmatrix} y_k\end{Bmatrix} {yk}第16项时, b k b_k bk的分母将会超过上述除法操作的分母限制范围 ( − 2 31 , 2 31 − 1 ) (-2^{31},2^{31}-1) (231,2311),同时也为了便于之后的OMP优化,我们继续对 b k b_k bk进行分解变换。
1 2 2 k − 1 = 1 2 × 1 2 × ⋯ × 1 2 ⏞ 2 k − 1 = 1 2 n × 1 2 m × 1 2 m × ⋯ × 1 2 m ⏞ [ 2 k − 1 m ] (14) \frac{1}{2^{2k-1}} =\overbrace{\frac{1}{2}\times \frac{1}{2}\times \dots \times \frac{1}{2}}^{2k-1} =\frac{1}{2^n}\times \overbrace{\frac{1}{2^m}\times\frac{1}{2^m}\times \dots \times \frac{1}{2^m}}^{[\frac{2k-1}{m}]}\tag{14} 22k11=21×21××21 2k1=2n1×2m1×2m1××2m1 [m2k1](14)
其中 n + [ 2 k − 1 m ] × m = 2 k − 1 n+[\frac{2k-1}{m}]\times m = 2k-1 n+[m2k1]×m=2k1,且 n < m < 16 n<m<16 n<m<16。同理可以得到 1 3 2 k − 1 \frac{1}{3^{2k-1}} 32k11

const int N = 500;			// pi的精确位数
const int TIMES = 1000;		// 算法迭代次数,即yk的项数
int b[TIMES][N] = { {0} };	// 存放bk项,因为其占用空间较大,所以定义为全局变量

int main(void)
{
	clock_t startTime = clock();
	
	int result[N] = { 0 }; // 存放最终结果

	int const TDN = 8;	// m 或者理解为并行的线程数
	int x[N] = { 0 };	// 存放1/2的m次方
	int y[N] = { 0 };	// 存放1/3的m次方
	int(*x1)[N] = new int[TDN][N]{ {0} }; // 存放1/2的2k-1次方
	int(*y1)[N] = new int[TDN][N]{ {0} }; // 存放1/3的2k-1次方

	// 计算1/2的m次方
	calc_div(x, 1, (int)pow(2, 2 * TDN), N);
	// 计算1/3的m次方
	calc_div(y, 1, (int)pow(3, 2 * TDN), N);
	// 计算1/2、1/3的n次方
	for (int k = 0; k < TDN; k++) {
		calc_div(x1[k], 1, (int)pow(2, 2 * k + 1), N);
		calc_div(y1[k], 1, (int)pow(3, 2 * k + 1), N);
	}
	// 计算ak*bk
	for (int k = 0; k < TDN; k++) {
		for (int i = 0; i < TIMES / TDN; i++) {
			// 计算bk
			calc_add(b[i * TDN + k], x1[k], N);
			calc_add(b[i * TDN + k], y1[k], N);
			calc_multi(x1[k], x, N);
			calc_multi(y1[k], y, N);
			
			// 计算ak*bk
			int a[N] = { 0 }; // 存放ak
			int t = 2 * (i * TDN + k) + 1;
			calc_div(a, 4, t, N);
			calc_multi(b[i * TDN + k], a, N);
		}
	}
	// 将最终结果相加/减
	for (int i = 0; i < TIMES; i++) {
		if (i % 2 == 1)
			calc_sub(result, b[i], N);
		else
			calc_add(result, b[i], N);
	}
	printf("The run time is: %.3fs\n", (clock() - (int)startTime) / 1000.0);

	// 打印pi
	printf("%d.", result[0]);
	for (int i = 1; i < N; i++)
	{
		printf("%d", result[i]);
	}
	printf("\n");
	delete[] x1;
	delete[] y1;
}

运行程序有如下结果
在这里插入图片描述

OMP优化

分别在计算 b k b_k bk a k b k a_kb_k akbk代码段前添加以下语句,展开for循环。

#pragma omp parallel for

运行程序后有如下结果
在这里插入图片描述

仿照积分法,同样计算欧拉恒等式法的OMP优化指标

相对加速比:
S ( P ) = 10.524 1.937 ≈ 5.433 S(P)=\frac{10.524}{1.937}≈5.433 S(P)=1.93710.5245.433
并行化效率:
E e u l a r = S ( P ) 8 ≈ 0.679 E_{eular}=\frac{S(P)}{8}≈0.679 Eeular=8S(P)0.679
相比于未进行OMP优化时的10.5秒,优化后的执行时间显著减少,观察计算 b k b_k bk a k b k a_kb_k akbk的代码,将第一层for循环拆开,分配到不同的核上执行,由于循环体内的程序每一次循环时都和前一次循环无关,并且不同次数的循环修改的内存地址不同,因此将循环拆开后,仍能计算出正确的结果。这是典型的以空间换效率,在不同地址存放每一次循环的结果,这样就避免了数据竞争的情况。

四、总结

积分法与欧拉恒等式法的对比

首先对比上文中积分法和欧拉恒等式法的计算通式:

  • 积分法

π = ∑ i = 0 N 4 N 1 + ( i N ) 2 , N → + ∞ π=\sum_{i=0}^N\frac{\frac{4}{N}}{1+(\frac{i}{N})^2},N\to +\infty π=i=0N1+(Ni)2N4,N+

  • 欧拉恒等式法

π = ∑ i = 1 N ( − 1 ) i − 1 4 2 i − 1 ( 1 2 2 i − 1 + 1 3 2 i − 1 ) , N → + ∞ π=\sum_{i=1}^N(-1)^{i-1}\frac{4}{2i-1}(\frac{1}{2^{2i-1}}+\frac{1}{3^{2i-1}}),N\to +\infty π=i=1N(1)i12i14(22i11+32i11),N+

积分法的收敛速度仅为 1 x 2 \frac{1}{x^2} x21,为二次收敛,而本文所列举的欧拉恒等式法为指数收敛,收敛速度极快。

OMP实现方式的对比

对比两者的实现方式,都使用了将最外层循环展开的方法,然而两者的并行化效率却不一样, E i n t e = 0.428 < E e u l a r = 0.679 < 1 E_{inte}=0.428<E_{eular}=0.679<1 Einte=0.428Eeular=0.679<1。造成并行化效率小于1的原因有以下两方面:

  • 每个并行体的计算量有差别
  • 在分发并行的时候,系统需要消耗资源。

针对这两个因素,我们可以将程序移植到Linux系统(双ARM核)上来做对照实验。

1.积分法

  • 无OMP优化
    在这里插入图片描述

  • OMP优化
    在这里插入图片描述
    可以计算此时的并行化效率
    E i n t e − l i n u x = S ( P ) 2 ≈ 1 E_{inte-linux}=\frac{S(P)}{2}≈1 Eintelinux=2S(P)1

2.欧拉恒等式法

  • 无OMP优化
    在这里插入图片描述

  • OMP优化
    在这里插入图片描述

同样可以计算:
E e u l a r − l i n u x = S ( P ) 2 ≈ 1 E_{eular-linux}=\frac{S(P)}{2}≈1 Eeularlinux=2S(P)1

通过上述对比,我们可以发现,在Linux下两种方法的并行化效率大致相同,且都约等于1。可见两种方法的并形体计算量基本一致,区别在于操作系统分发并行任务时的开销不同。

接着分析两种方法的并行化效率不同的区别。

本次实验的处理器为四核八线程的英特尔酷睿i7-7700HQ,就是说除了四个核心所能处理的四线程外,它还拥有四个超线程。

超线程HT(Hyper-Threading)技术是在单个核心处理单元中集成两个逻辑处理单元,也就是一个实体内核(共享的运算单元)拥有两个逻辑内核(有各自独立的处理器状态)。而其余部分如ALU(整数运算单元)、FPU(浮点运算单元)、L2 Cache(二级缓存)则保持不变,这些部分是被分享的。

这样就可以看出差别,本次实验中积分法大部分运算为浮点运算,进行OMP加速时运行在同一个核心上的两个线程将会争夺一个FPU,所以其加速比不能达到或接近核心(超线程)数量。而欧拉恒等式法全为整型运算,运行在同一个核心上的两个线程能够分别使用ALU和FPU,不会出现竞争情况,所以其加速比大于实际核心数量。

完成程序在这里https://download.csdn.net/download/qq_42688495/12291963

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

多线程之基于积分法与欧拉恒等式法的圆周率计算及OMP优化 的相关文章

  • SVPWM的MATLAB建模

    异步电机矢量控制20讲 xff1a SVPWM的simulink仿真 xff08 总第38讲 xff09 扇区判断 注意 xff0c 这个N是二进制转来的十进制数 波形对应出来的扇区是 5 6 1 2 3 4 如果改变三相电压输入的相位 x
  • Java要素察觉

    简介 xff1a 主要内容来源于b站刘二大人Java课程 xff0c 旨在记录课程中的重要内容 Java课程记录 xff08 课程号作为标题 xff09 02 数据类型03 数组与字符串05 类与对象07 继承08 方法重载 方法重写和多态
  • vscode配置gitee(码云)实现步骤

    第一步 1 百度搜索Git xff0c 出现的第一个网站 xff08 如下图 xff09 Git xff09 2 下载 3 下载之后 双击安装 xff08 安装过程中只需要默认下一步 不需要多余操作 放心大胆的点击下一步 xff09 第二步
  • ROS读取MPU6050数据

    上一篇讲到使用I2C连接Jetson Nano和MPU6050并使用python读取 xff0c 本次基于roscpp连接读取IMU数据 RTIMULib RTIMULib是本次使用的IMU库 xff0c 支持多种常见的IMU模块 xff0
  • 关于navicat报错:Server unexpectedly closed network connection

    破解navicat后 使用navicat连接本地虚拟机 发现出现以下错误 在百度以及谷歌上面查找很多博客 发现我这里的报错信息跟他们不一样 解决方法 1 打开本地虚拟机 进入mysql mysql span class token oper
  • 学会查看官方文档

    曾经经历过的误区 从刚开始接触编程开始 xff0c 基本上接触新事物 xff0c 第一件事情就是去找博客 xff0c 或者买书 往往只需要使用的一个很小的知识点 xff0c 却购买了好几本不同的书籍 事后证明 xff0c 并没有什么太大的用
  • QGroundControl如何进行二次开发

    QGroundControl如何进行二次开发 QGroundControl是一个开源的地面站软件 xff0c 你可以通过以下步骤进行二次开发 xff1a 1 下载并安装QGroundControl 首先需要从QGroundControl的官
  • C 结构体指针malloc分配问题

    C语言中关于结构体指针的内存分配问题 话不多说先上一段代码 span class token keyword typedef span span class token keyword struct span span class toke
  • 这是一个用于记录学习经验的博客

    写在前面 本科时期科研经历较少 xff0c 硕士期间越来越多地开始接触计算机相关的软件 算法 项目等 从2020年入学至今 xff0c 也学习到了一些相关的知识与经验 过去都是通过word的方式记录进展与经验 从今天起我也想尝试通过博客的方
  • ARM64架构的Linux系统中编译C++程序报错fatal error: sys/io.h: No such file or directory

    原因是不同的Linux平台的 io h 放置的位置不同 Windows下的io h直接包含即可 xff1b Linux平台下在sys文件夹下 xff1b ARM架构的系统中在sys文件夹下 xff0c 而且名字也不一样 xff0c 变成了u
  • 矩阵的QR分解

    Gram Schmidt正交化 在提到矩阵的QR分解前 xff0c 必须要提到Gram Schmidt方法 xff0c 理论上QR分解是由Gram Schmidt正交化推出来的 那么Gram Schmidt正交化究竟是什么 在三维空间存在直
  • 常见数学符号及其读法

    大写 小写 英文注音 国际音标注音 中文注音 alpha alfa 阿耳法 beta beta 贝塔 gamma gamma 伽马 deta del
  • cartographer环境配置及运行

    文章目录 1 首先安装ROS2 安装eigen33 安装ceres4 安装cartographer5 试运行总结 xff1a 系统 xff1a Ubuntu 18 04 1 首先安装ROS 在无网络限制的情况下参考官网安装 ref xff1
  • SLAM会议笔记(一)LOAM

    LOAM Lidar Odometry and Mapping in Real time ABSTRACT 将复杂的SLAM问题分离为两个算法 xff0c 一个高频低精度的运动估计 xff0c 另一个低一个数量级的点云匹配和配准算法 REL
  • 相机&IMU内参及外参标定

    1 使用工具 xff1a https github com ethz asl kalibr git 2 特点支持多个相机的内参外参标定 xff0c 即使视域没有重叠 xff1b 支持相机 amp IMU之间标定 xff1b 支持IMU与IM
  • SLAM会议笔记(二)Real-time DEMO

    Real time Depth Enhanced Monocular Odometry Abstract 利用图像和稀疏的深度图做运动估计 xff0c 同时利用三角量测和运动估计得到位置深度的突出图像特征点的深度 xff0c 使用光束平差法
  • SLAM会议笔记(三)V-LOAM

    Visual lidar Odometry and Mapping Low drift Robust and Fast Abstract 提出了一种新的使用激光雷达里程计和视觉里程计的框架 xff0c 提升了表现 xff0c 特别是在剧烈运
  • SLAM会议笔记(四)Lego-LOAM

    LeGO LOAM Lightweight and Ground Optimized Lidar Odometry and Mapping on Variable Terrain Abstract 提出一种轻量级的ground optimi
  • SLAM会议笔记(五)LLOAM

    LLOAM LiDAR Odometry and Mapping with Loop closure Detection Based Correction Abstract 在LOAM的基础上加入了回环检测 xff0c 实现了雷达SLAM的
  • C++基础:第三章 对象与基本类型

    文章目录 第3章 对象与基本类型第1节 初始化 赋值语句第2节 类型详述类型描述类型种类划分与类型相关的标准未定义部分变量 第3节 复合类型 xff1a 从指针到引用指针指针特点相关操作符指针的定义 96 void 96 指针指针的指针指针

随机推荐

  • C++基础:第四章 数组、vector和字符串

    文章目录 第4章 数组 vector和字符串第1节 数组注意事项数组的复杂声明数组中元素的访问数组到指针的隐式转换获得s指向数组开头和结尾的指针数组的其他操作C字符串多维数组 第2节 vector构造和初始化元素的索引和遍历迭代器itera
  • C++基础:第五章 表达式基础与详述

    第五章 表达式基础与详述 第1节 基础 xff1a 引入 表达式由一到多个操作数组成 xff0c 可以求值并 xff08 通常会 xff09 返回求值结果 xff08 函数的调用是一种表达式 xff0c 有时函数不会返回求值结果 xff09
  • C++基础:第六章 语句

    第六章 语句 第1节 语句基础 常见类别 xff1a 表达式语句 xff0c 求值后丢弃 2 43 3 空语句复合语句 xff0c 用大括号 xff0c 形成独立的域 顺序语句 按先后顺序执行实际执行顺序可能产生变换 xff08 编译器优化
  • C++基础:第七章 函数

    第七章 函数 第1节 函数基础 栈帧结构 函数的外部链接 第2节 函数详解 传值 传址 传引用 传参数时的类型退化 xff0c 传数组时函数形参退化成指针 xff0c 所以形参不要写数组个数 多维数组作为函数参数时 void fun int
  • C++基础:第八章 深入IO

    第八章 深入IO 第1节 序 第2节 IOStream概述 流式IO而非记录IO 处理的主要问题 表示形式的变化 xff1a 使用格式化 解析在数据的内部表示与字符序列之间切换与外部设备的通信 xff1a 针对不同的外部设备引入不同的处理逻
  • 在vscode终端安装vue构建工具vite

    首先确保已安装npm 第一步 xff1a 全局安装yarn 0 打开cmd xff08 windows 43 R xff09 1 输入安装命令 npm install g yarn 2 如果能看到版本号 xff0c 则安装成功 yarn v
  • cmake相关:sudo make install后的卸载

    sudo make install后的卸载 我们知道linux中一般的编译一个package的顺序是 span class token function git span clone package git span class token
  • 提取rosbag中的图像话题存为本地图像

    新建存放图片文件夹 首先运行ros master roscore 在目标文件夹目录下运行 rosrun image view extract images sec per frame 61 0 05 image 61 lt ROSIMAGE
  • matlab循环读取文件

    一般情况下 xff0c 假如我要读取一个名为a txt的文件 xff0c 只需要利用下面的语句 xff1a a span class token operator 61 span span class token function load
  • 使用OpenMVG获取相机位姿的方法

    在生成sfm data bin文件后 xff0c 在文件目录下执行 openMVG main ConvertSfM DataFormat binary span class token operator span i yoursfm dat
  • Ubuntu修改文件夹下面所有文件权限的方法

    ubuntu修改文件夹下所有文件的权限 命令为 xff1a sudo chmod span class token operator span R 777 filename filename为要修改的文件夹名字 R应该是表示递归修改file
  • 写出对js事件,事件流,事件对象的理解

    事件 JavaScript 使我们有能力创建动态页面 事件是可以被 JavaScript 侦测到的行为 网页中的每个元素都可以产生某些可以触发 JavaScript 函数的事件 比方说 xff0c 我们可以在用户点击某按钮时产生一个 onC
  • UDP实时图像传输

    写在前面 首先问个问题 xff0c 为什么要用UDP传输图像 xff0c 而不是TCP xff1f TCP是我们经常使用的通信协议 xff0c 从认识它的第一天起 xff0c 就应该知道 xff0c 它非常稳 xff0c 丢包率超低 但是一
  • 机器学习 | 使用k-近邻算法实现手写识别系统

    KNN概述 k 近邻算法就是通过计算不同特征值之间的距离来进行分类的算法 假设我们现在有一个样本集 xff0c 每个样本都有几个特征用来描述这个样本 xff0c 以及一个它所属分类的标签 当我们拿到一个没有标签的样本时 xff0c 该如何判
  • Windows下如何查看一个process内有哪些thread

    从https docs microsoft com en us sysinternals downloads pslist下载PsTools xff0c 解压后找到pslist exe并移动到C盘任一目录下 xff0c 使用说明都在Psto
  • 机器人路径规划之动态窗口法

    动态窗口法 Dynamic Window Approach 概述 DWA是一种基于速度的局部规划器 xff0c 可计算达到目标所需的机器人的最佳无碰撞速度 程序实现 DWA算法主要分三步 xff1a 计算动态窗口计算最优 v
  • cso(布谷鸟)算法优化神经网络参数

    之前写了一篇pso工程上使用方法 xff0c 这一篇使用布谷鸟算法 xff0c 相关的原理也比较多的介绍了 目前实验结果还是pso快一点 一 布谷鸟算法介绍 布谷鸟搜索算法 xff0c 是 由剑 桥 大 学YANG等在文献 中提出的一种群智
  • 多线程之线程安全(Thread Safety)

    什么是线程安全 Thread Safety xff1f 怎样才能做到线程安全 xff1f 线程安全 线程安全指某个函数 函数库在多线程环境中被调用时 xff0c 能够正确地处理多个线程之间的共享变量 xff0c 使程序功能正确完成 数据类型
  • 多线程之简易注册验证程序

    问题描述 使用VC2010或以上版本编写一个多线程注册验证程序 xff0c 要求 xff1a 通过对话框输入若干人的学号和姓名 xff0c 并存入列表中作为注册记录 用户输入一个学号 xff0c 程序能通过多线程的方式与注册记录比对来验证其
  • 多线程之基于积分法与欧拉恒等式法的圆周率计算及OMP优化

    文章目录 一 问题描述二 积分法算法推导编程实现OMP优化 三 欧拉恒等式算法推导编程实现前期准备加法减法乘法除法 算法实现 OMP优化 四 总结积分法与欧拉恒等式法的对比OMP实现方式的对比 一 问题描述 分别采用积分法和欧拉恒等式计算