1. 程式人生 > >AVX 指令集並行技術優化積分計算圓周率 π

AVX 指令集並行技術優化積分計算圓周率 π

通過 AVX 指令集並行技術優化積分計算圓周率 π

完整程式碼和解釋如下

// AVX_PI.cpp : 定義控制檯應用程式的入口點。
//

#include "stdafx.h"
#include <iostream>
#include <immintrin.h>
#include <time.h>

#include "timer.h"

double compute_pi_naive(size_t dt)
{
	double pi = 0.0;
	double delta = 1.0 / dt;
	for (size_t i = 0; i < dt; i++)
	{
		double x = (double)i / dt;
		pi += delta / (1.0 + x*x);
	}

	return pi*4.0;
}

double compute_pi_avx(size_t dt)
{
	double pi = 0.0;
	double delta = 1.0 / dt;

	__m256d ymm0, ymm1, ymm2, ymm3, ymm4;

	ymm0 = _mm256_set1_pd(1.0);	// 注意並不是對應一條指令,而是多條指令混合而成
	ymm1 = _mm256_set1_pd(delta);
	ymm2 = _mm256_set_pd(delta * 3, delta * 2, delta, 0.0);	// 0.0, delta, 2*delta, 3*delta
	ymm4 = _mm256_setzero_pd();

	for (int i = 0; i <= dt - 4; i += 4)
	{
		ymm3 = _mm256_set1_pd(i * delta);	// 歸一化構造 x(積分割槽間為 0-1)
		ymm3 = _mm256_add_pd(ymm3, ymm2);	// 分別累加四項(分別相差一個delta)
		ymm3 = _mm256_mul_pd(ymm3, ymm3);	// 平方
		ymm3 = _mm256_add_pd(ymm0, ymm3);	// + 1
		ymm3 = _mm256_div_pd(ymm1, ymm3);   // delta 向量除
		ymm4 = _mm256_add_pd(ymm4, ymm3);	// 累加
	}
#ifndef _WIN32
	double tmp[4] __attribute__((aligned(32)));
#else
//#pragma pack(8)
	__declspec(align(32))	// arm 下的記憶體邊界對齊使用 __align
	double tmp[4];
//#pragma pack()
#endif
	_mm256_store_pd(tmp, ymm4);
	pi = tmp[0] + tmp[1] + tmp[2] + tmp[3];

	return pi * 4.0;

}

int _tmain(int argc, _TCHAR* argv[])
{
	size_t dt = 1e10;

	Timer timer;
	double pi_naive = compute_pi_naive(dt);
	printf("Pi = %lf, %lfms\n", pi_naive, timer.elapsed());

	timer.restart();
	double pi_avx = compute_pi_avx(dt);
	printf("Pi = %lf, %lfms\n", pi_avx, timer.elapsed());
	
	return 0;
}

最後輸出的結果,獲得了 3 倍多的加速(耗時不到原來序列版本的 1/4 )