- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我希望使用不同类型的 HPC 范例来实现一个简单的 Mandelbrot 集绘图器,展示它们的优点和缺点以及它们的实现的难易程度。想想 GPGPU (CUDA/OpenACC/OpenMP4.5)、线程/OpenMP 和 MPI。并使用这些示例为刚接触 HPC 的程序员提供帮助并了解可能性。代码的清晰度比从硬件中获得绝对的顶级性能更重要,这是第二步;)
因为这个问题对于并行化来说是微不足道的,而且现代 CPU 可以使用 vector 指令获得巨大的性能,所以我还想结合 OpenMP 和 SIMD。不幸的是,只需添加一个 #pragma omp simd
不会产生令人满意的结果,并且使用内在函数不是非常用户友好或面向 future 。或者 pretty .
幸运的是,正在对 C++ 标准进行改进,这样应该更容易通用地实现 vector 指令,如 TS 中所述:"Extensions for parallelism, version 2" ,特别是关于数据并行类型的第 9 节。可以找到 WIP 实现 here ,基于VC可以找到here .
假设我有以下类(已对其进行更改以使其更简单一些)
#include <stddef.h>
using Range = std::pair<double, double>;
using Resolution = std::pair<std::size_t, std::size_t>;
class Mandelbrot
{
double* d_iters;
Range d_xrange;
Range d_yrange;
Resolution d_res;
std::size_t d_maxIter;
public:
Mandelbrot(Range xrange, Range yrange, Resolution res, std::size_t maxIter);
~Mandelbrot();
void writeImage(std::string const& fileName);
void computeMandelbrot();
private:
void calculateColors();
};
以及以下 computeMandelbrot()
的实现使用 OpenMP
void Mandelbrot::computeMandelbrot()
{
double dx = (d_xrange.second - d_xrange.first) / d_res.first;
double dy = (d_yrange.second - d_yrange.first) / d_res.second;
#pragma omp parallel for schedule(dynamic)
for (std::size_t row = 0; row != d_res.second; ++row)
{
double c_imag = d_yrange.first + row * dy;
for (std::size_t col = 0; col != d_res.first; ++col)
{
double real = 0.0;
double imag = 0.0;
double realSquared = 0.0;
double imagSquared = 0.0;
double c_real = d_xrange.first + col * dx;
std::size_t iter = 0;
while (iter < d_maxIter && realSquared + imagSquared < 4.0)
{
realSquared = real * real;
imagSquared = imag * imag;
imag = 2 * real * imag + c_imag;
real = realSquared - imagSquared + c_real;
++iter;
}
d_iters[row * d_res.first + col] = iter;
}
}
}
我们可以假设 x 和 y 方向的分辨率都是 2/4/8/.. 的倍数,具体取决于我们使用的 SIMD 指令。
不幸的是,关于std::experimental::simd
的在线信息很少。 .据我所知,也没有任何重要的例子。
在 Vc git 存储库中,有一个 Mandelbrot 集合计算器的实现,但它非常复杂,并且由于缺少注释而很难理解。
很明显,我应该在函数 computeMandelbrot()
中更改 double 的数据类型,但我不确定是什么。 TS 提到了一些类型 T 的两种主要新数据类型,
native_simd = std::experimental::simd<T, std::experimental::simd_abi::native>;
和
fixed_size_simd = std::experimental::simd<T, std::experimental::simd_abi::fixed_size<N>>;
使用 native_simd
最有意义,因为我在编译时不知道我的界限。但是我不清楚这些类型代表什么,是 native_simd<double>
单个 double 还是执行 vector 指令的 double 集合?那么这个系列中有多少 double ?
如果有人能给我指出使用这些概念的示例,或者给我一些关于如何使用 std::experimental::simd 实现 vector 指令的指示,我将不胜感激。
最佳答案
这是一个非常基本的实现,它可以工作(据我所知)。测试 vector 中哪些元素的绝对值大于 2 的方法非常繁琐且效率低下。一定有更好的方法来做到这一点,但我还没有找到。
我在 AMD Ryzen 5 3600 上获得了大约 72% 的性能提升,并为 g++ 提供了 -march=znver2
选项,这低于预期。
template <class T>
void mandelbrot(T xstart, T xend,
T ystart, T yend)
{
namespace stdx = std::experimental;
constexpr auto simdSize = stdx::native_simd<T>().size();
constexpr unsigned size = 4096;
constexpr unsigned maxIter = 250;
assert(size % simdSize == 0);
unsigned* res = new unsigned[size * size];
T dx = (xend - xstart) / size;
T dy = (yend - ystart) / size;
for (std::size_t row = 0; row != size; ++row)
{
T c_imag = ystart + row * dy;
for (std::size_t col = 0; col != size; col += simdSize)
{
stdx::native_simd<T> real{0};
stdx::native_simd<T> imag{0};
stdx::native_simd<T> realSquared{0};
stdx::native_simd<T> imagSquared{0};
stdx::fixed_size_simd<unsigned, simdSize> iters{0};
stdx::native_simd<T> c_real;
for (int idx = 0; idx != simdSize; ++idx)
{
c_real[idx] = xstart + (col + idx) * dx;
}
for (unsigned iter = 0; iter != maxIter; ++iter)
{
realSquared = real * real;
imagSquared = imag * imag;
auto isInside = realSquared + imagSquared > stdx::native_simd<T>{4};
for (int idx = 0; idx != simdSize; ++idx)
{
// if not bigger than 4, increase iters
if (!isInside[idx])
{
iters[idx] += 1;
}
else
{
// prevent that they become inf/nan
real[idx] = static_cast<T>(4);
imag[idx] = static_cast<T>(4);
}
}
if (stdx::all_of(isInside) )
{
break;
}
imag = static_cast<T>(2.0) * real * imag + c_imag;
real = realSquared - imagSquared + c_real;
}
iters.copy_to(res + row * size + col, stdx::element_aligned);
}
}
delete[] res;
}
整个测试代码(从auto test = (...)
开始)编译为
.L9:
vmulps ymm1, ymm1, ymm1
vmulps ymm13, ymm2, ymm2
xor eax, eax
vaddps ymm2, ymm13, ymm1
vcmpltps ymm2, ymm5, ymm2
vmovaps YMMWORD PTR [rsp+160], ymm2
jmp .L6
.L3:
vmovss DWORD PTR [rsp+32+rax], xmm0
vmovss DWORD PTR [rsp+64+rax], xmm0
add rax, 4
cmp rax, 32
je .L22
.L6:
vucomiss xmm3, DWORD PTR [rsp+160+rax]
jp .L3
jne .L3
inc DWORD PTR [rsp+96+rax]
add rax, 4
cmp rax, 32
jne .L6
关于c++ - 使用 OpenMP 线程和 std::(experimental::)simd 计算 Mandelbrot 集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63488675/
我现在在 Mandelbrot 集的 DirectX 11 版本上工作了几天。到目前为止,我所做的是创建一个带有纹理的四边形。我可以使用 Pixel Shader 为点着色,但由于某种原因,Pixel
我在 Javascript 上编写了一个程序,用于创建 mandelbrot 分形,并将其绘制在 html Canvas 中。我的渲染方法是每行迭代,从 0 到 500 像素,然后简单地执行一个循环,
我的类(class)布置了一项作业,要求我编写一个程序来绘制曼德尔布洛特图形。 我们必须基本上让程序绘制结果的位图。 问题是,我的 CalcMBF 函数只输出 2 作为 Mandelbrot 数。 我
我认为问题在于我如何将笛卡尔坐标转换为复数,但我现在知道如何操作了。你能解释一下我应该如何转换吗?这是我尝试过的: double c_Im = (y + (maxIm - minIm)) / heig
我是 C++ 编程的新手,为了改进,我正在尝试制作一个 mandelbrot set consol 应用程序。我已经让它几乎完美地工作:图像生成,我可以放大/缩小,并且非常容易地四处移动。不过,我遇到
我想使用 Java 生成 Mandelbrot 集的 PNG 照片,输出应该可以在 Google 图片搜索中轻松找到。 该集合定义为以下序列: z_n+1 = z_n^2 + c 其中 c 和 z 是
我用 Java 编写了一个 Mandelbrot 集分形,并包含了在一定程度上平移和放大分形的功能。唯一的问题是,当我平移图像并尝试放大时,它看起来好像试图放大中心并平移一点。平移和缩放并不是真正的平
我用 python 编写了 Mandelbrot 集,但它看起来很奇怪,所以我搜索了平滑的颜色。我已经使用对数和线性插值编写了一个平滑的着色函数,但无论我尝试什么,我都无法得到我想要的: self.p
我编写了一个简单的片段着色器来渲染 mandelbrot 集。我正在使用 c 语言和使用 glsl 的 opengl 执行此操作。 #version 330 core in vec2 fCoord;
我正在尝试制作一个程序,通过制作一个 .PPM 文件来生成标准 Mandelbrot 集的图像。该程序没有生成有效的 PPM 文件,我不知道为什么。 这是我的代码: #include #includ
我知道已经回答了很多关于此的问题。然而,我的略有不同。每当我们实现我所理解的平滑着色算法时。 mu = 1 + n + math.log2(math.log2(z)) / math.log2(2)
mandelbrot 集包含 mandelbrot 迭代有界的点,迭代点永远不会“逃逸”。 让我们将边界定义为点,其中迭代点在 N 次迭代后逃逸(逃逸我的意思是与原点的距离变得大于 2)。 是否可以保
我一直在做 Mandelbrot 集并尝试缩放,但缩放模式变得非常麻烦。当我缩放时,它会完美缩放,但图像尺寸会缩小到原始尺寸的一半。下次我再次缩放时,图片尺寸会增加并尝试跳过查看窗口。代码在 c++/
我目前正在编写一个程序来生成非常巨大的(65536x65536 像素及以上)Mandelbrot 图像,并且我想设计一个光谱和着色方案来使它们公平。 wikipedia featured mandel
谁能解释一下扰动是如何描述的in this paper加速渲染 Mandelbrot 集? 我知道如何使用对每个像素执行多次迭代的传统方法来渲染 Mandelbrot 集,但我不太明白那篇论文中描述的
这是我尝试使用 Pygame 模块在 Python 3.5 中编写 Mandelbrot 集。 import math, pygame pygame.init() def mapMandelbrot(
我正在使用 C 编写以下代码。到目前为止,它一直在工作,并且已缩放到正确的级别等,但是我正在努力让颜色按我想要的方式工作。理想情况下,无论颜色如何,我都希望得到这样的结果: 但是我的程序如下所示,目前
我可以生成从 minReal 到 maxReal 以及从 minImaginary 到 maxImaginary 的 Mandelbrot 集的 400x400 图像。所以, makeMandel(m
我正在编写绘制 Mandelbrot 集版本的代码。当它运行时,它接受两个输入 a 和 b,并将其转换为一个复数(例如 complex(a,b))。然后它绘制一个 Mandelbrot 集,其中 z
尝试使用与我在使用 TBB(线程构建块)运行时使用的代码相同的代码(有点)。 我对 OpenCL 没有太多经验,但我认为大部分主要代码是正确的。我相信错误在 .cl文件,它在那里进行数学运算。 这是我
我是一名优秀的程序员,十分优秀!