- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
这是一个在 .ppm 文件中输出 mandelbrot 分形的代码。我该如何优化它?
#include<bits/stdc++.h>
using namespace std;
int findMandelbrot(double cr, double ci, int max_iterations)
{
int i = 0;
double zr = 0.0, zi = 0.0;
while (i < max_iterations && zr * zr + zi * zi < 4.0)
{
double temp = zr * zr - zi * zi + cr;
zi = 2.0 * zr * zi + ci;
zr = temp;
++i;
}
return i;
}
double mapToReal(int x, int imageWidth, double minR, double maxR)
{
double range = maxR - minR;
return x * (range / imageWidth) + minR;
}
double mapToImaginary(int y, int imageHeight, double minI, double maxI)
{
double range = maxI - minI;
return y * (range / imageHeight) + minI;
}
int main()
{
ifstream f("input.txt");
int imageWidth, imageHeight, maxN;
double minR, maxR, minI, maxI;
if (!f)
{
cout << "Could not open file!" << endl;
return 1;
}
f >> imageWidth >> imageHeight >> maxN;
f >> minR >> maxR >> minI >> maxI;
ofstream g("output_image.ppm");
g << "P3" << endl;
g << imageWidth << " " << imageHeight << endl;
g << "255" << endl;
double start = clock();
for (int i = 0; i < imageHeight; i++)
{
for (int j = 0; j < imageWidth; j++)
{
double cr = mapToReal(j, imageWidth, minR, maxR);
double ci = mapToImaginary(i, imageHeight, minI, maxI);
int n = findMandelbrot(cr, ci, maxN);
int r = ((int)sqrt(n) % 256);
int gr = (2*n % 256);
int b = (n % 256);
g << r << " " << gr << " " << b << " ";
}
g << endl;
if(i == imageHeight / 2) break;
}
cout << "Finished!" << endl;
double stop = clock();
cout << (stop-start)/CLOCKS_PER_SEC;
return 0;
}
我一直走到 imageHeight/2 因为在 photoshop 中我可以只复制另一半。我在考虑对数幂,但尝试了一些东西并且只适用于整数......
最佳答案
有很多方法可以优化 Mandelbrot 分形。
一种方法是针对您的 CPU 甚至 GPU 优化代码。令人印象深刻的加速显示在:Mandelbrot with SSE, AVX and OpenCL .这将内部循环优化了将近 1000 倍。速度提高了 3 个数量级。
但是还有其他的优化方式。您已经提到的第一个:mandelbrot 集在 y=0 处镜像。所以你只需要一半。有一些更简单的方法可以避免运行内部循环。如果您向下滚动 Wikipedia on Mandelbrot到优化,您会看到“心形/灯泡检查”。这是对苹果形主要部分或直接在其左侧的圆中的点的简单检查。对于可以涵盖很多点的海报。
我见过的另一种加速方法是在生成预览时使用距离估计(也在维基百科上)方法或仅使用黑白设置的 mandelbrot 轮廓。计算图像中的随机点,如果在 mandelbrot 集之外,则绘制一个圆,其半径由距离估计方法给出。该圆圈中的任何东西都不是 mandelbrot 集的一部分。这可以快速覆盖 mandelbrot 集之外的许多点。
还有一些近似结果的方法可能不会产生完美的图像,但通常已经足够好了。例如:
计算边界后的点,其中像素需要 N 和 N+1 次迭代才能逃逸。 N+1 和 N+2 相同。这两个边界之间的所有内容都需要 N 次迭代。
计算矩形的边界(从整个图像开始)。如果边界全部进行 N 次迭代,则矩形内部进行 N 次迭代并被填充。否则将矩形分成 4 份并重复每份。通过计算 2 或 3 像素宽的边框可能会改善结果,但保存的会更少。
以低分辨率计算图像,然后将分辨率加倍以保持计算点。检查图像,如果 5x5 个原始点具有相同的 N,则在内部 3x3 点周围填充一个矩形(也适用于 3x3、7x7、9x9 等点)。未填写的分数由您计算。然后重复整个过程,直到你得到最终的解决方案。
这是最难做到的,我只见过它的一种实现方式。这个想法是靠近在一起的点在迭代中表现相同。如果您迭代一个 3x3 点的网格(首先覆盖整个图像),您可以使用牛顿插值法对中间点的值进行插值。这工作得很好——直到它不工作。
因此,除了 3x3 点网格之外,您还迭代了 4 个测试点,即每个网格单元的中间。对这 13 个点进行 8 次迭代,然后从网格点中插入 4 个测试点。如果计算结果和插值结果相差太大(这是困难的部分),您将丢弃最后 8 次迭代并将网格 segmentation 为 4 个半尺寸网格。您插入的缺失点。重复直到达到最终分辨率。
即使它只适用于几次迭代,潜在的好处也是巨大的。假设您想要 40000 x 40000 像素的图像。如果 SOI 在第一次 segmentation 之前工作 10 个循环(80 次迭代),那么您可以通过计算 1040 和一些插值和检查来节省 80 * 40000 * 40000 = 128_000_000_000 次迭代。或者加速 123_076_923,8 个数量级。但仅限于前 80 次迭代。随着网格被越来越多地划分,加速变得越来越小。但是,节省的每一点都会累加起来。
此方法的优点在于适用于平滑/连续着色或映射到高度。其他方法仅适用于将迭代映射到色带。
关于c++ - 优化 Mandelbrot 分形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44354589/
我正在尝试创建带有固定三 Angular 形导航的网页。 问题是我无法将较小的三 Angular 形放入大三 Angular 形中,如下图所示。 当调整窗口大小时三 Angular 形正在改变它的 A
我目前正在使用 Angular-material,但我在另一个项目中遇到了一种情况,迫使我使用类似 angular material chips 的东西。效果如本链接所述。 对我来说主要的麻烦是我想在
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 6 年前。 Improve this ques
我通过将一个正方形旋转 45 度创建了一个菱形: .shape { height: 50px; width: 50px; transform: rotate(45deg); } 是否
我使用 css 创建了一个三 Angular 形: .box { width: 0; height: 0; border-style: solid; border-width: 540px 964px
如何创建边框三 Angular 形? 我唯一能想到的就是做一个三 Angular 形 .triangle { width: 0; height: 0;
我想创建一个旋转函数,在该函数中我的三 Angular 形可以像轮子一样自行旋转,但我与移动三 Angular 形的部分代码发生冲突,我尝试了许多解决方案但没有成功,也许如果你们中的一个人知道它会对人
我正在使用线性垫步进器。 它与 next 一起工作正常。我进行 api 调用,如果成功,则调用 stepper-next 事件而不是使用 matStepperNext 指令。 现在,当用户在第 1 步
我想根据用户的 onClick 事件将 V 形从 down 更改为 up。我尝试过使用其他人的其他示例,但没有成功。 这是我的JSFiddle . 最佳答案 嗯,您的 JSFiddle 设置存在一些问
我想在鼠标单击的地方绘制一个 2D 三 Angular 形。已经制作了鼠标事件处理程序,并且可以看到鼠标单击的点。我在缓冲区对象中写入了三 Angular 形的顶点位置。它将是三 Angular 形大
有人可以告诉我我在 Javascript 中的帕斯卡三 Angular 形上做错了什么吗?我看到一个已经存在的使用递归的线程,但是,在没有逐字复制的情况下,在我看来,代码看起来太相似,无法破译我做错了
我必须为我的类(class)使用星号制作一个三 Angular 形和倒三 Angular 形。 我已经制作了上半部分,但是,我在制作上下颠倒的部分时遇到了很大的麻烦 for(var count=1;
我想获取围绕一个点的三 Angular 形的点,其中面指向指定法线的方向。我将使用 THREE.js 将它们添加到 BufferGeometry。 非常粗略的绘图: 这是我到目前为止的代码: //Th
我从编程开始。我正在使用 JavaScript。 为了练习,我打印了一个像这样的三 Angular 形: * ** *** **** ***** 但我想从右向左打印,如下所示: * **
我需要在 Joint JS 中创建一些以圆形源开头并以三 Angular 形结尾的链接,反之亦然,得到了这个,但它不起作用: var link1 = new joint.dia.Link({
这个问题已经有答案了: 奥 git _a (1 个回答) 已关闭 6 年前。 我做了一些安静的搜索,发现了很多将星星和其他形状输出到无数图案中的方法,但我还没有找到任何关于如何使用用户生成的短语来做到
我正在尝试仅使用递归打印出字母 V 的形状。我在这个网站上看到了一些与我的问题相关的代码,但大多数使用循环而不是递归。 这是我的代码: public class Pattern { pub
这个问题在这里已经有了答案: How to Make A Chevron Arrow Using CSS? (10 个答案) 关闭 7 年前。 我想给this triangle中间略有下降,我不想要
我的问题是关于使用 Javascript 对其边进行三 Angular 形评估。以下代码是非常初始的版本,即使它可以工作。我想知道它是否可以更简化,或者有其他方法可以达到相同的结果。 谢谢! let
function makeLine(length) { var line = ""; for (var i = 1; i <= length; i++) { for (var j =
我是一名优秀的程序员,十分优秀!