【问题标题】:Mandelbrot set reaches to its limit way too soon曼德布罗集很快达到极限
【发布时间】:2012-01-31 21:46:06
【问题描述】:

我正在计算 mandelbrot 集,能够使用 OpenGL 将其缩放并打印到屏幕上。

如您所知,mandelbrot 集由一个矩形(右上角和左下角)定义,每次我“放大”和“缩小”时,我都会通过将左下角移动到右上角来更改以下点侧和右上角点反之亦然。最终,这 2 个点应该彼此相遇并完成缩放过程。
根据许多 YOUTUBE 电影,我可以清楚地看到有些电影可以让您达到 1000 倍变焦。在我的程序中,我几乎无法达到 X6。在调试时我可以看到我的 2 点,它们定义了 mandelbrot 集相互到达(x1,y1) = (x2,y2)
几件事:
(x1,y1) & (x2,y2) 被定义为浮点数。我应该使用 double 代替吗? 我的 mandelbrot 由 (512X512) 点定义。够了吗?虽然我不确定它是否与问题有关。

我面临的另一个问题是 - 我将集合打印为高度图(3D 集合)。当每个 Y 分量代表某个点达到无穷大所需的迭代次数时。但是,每次我放大整个集合时,我的相机位置都会越来越高,最终我的相机被集合消耗掉了。有没有办法计算差异并将相机从集合中移开(相应地从缩放点移开?)

计算集合的代码:

double ratiox = instance->foundPointOnHost.x / ((instance->constVal[1][0] - instance->constVal[0][0]));;
            double ratioy = 1-instance->foundPointOnHost.z / ((instance->constVal[1][1] - instance->constVal[0][1]));;
            double xrange = instance->m_GraphConfig.xru-instance->m_GraphConfig.xld;
            double yrange = instance->m_GraphConfig.yru-instance->m_GraphConfig.yld;
            instance->m_GraphConfig.xld += 5*direction*0.005*ratiox*xrange;
            instance->m_GraphConfig.xru -= 5*direction*0.005*(1.-ratiox)*xrange;
            instance->m_GraphConfig.yld += 5*direction*0.005*(1.-ratioy)*yrange;
            instance->m_GraphConfig.yru -= 5*direction*0.005*ratioy*yrange;  

几件事:

instance->FoundPointOnHost = 我要放大的点。
instance->constVal = 包含集合的原始大小(开头等于 [xru,yru] [xld,yld])
(xru,yru) = 集合的右上角 (xld,yld) = 集合的左下角点

谢谢!

【问题讨论】:

  • 你能添加代码来解释你如何每一步更新 (x1,y1) 和 (x2,y2) 吗?
  • Cris Nash:我添加了代码,谢谢!
  • 我还想补充一点,ratioX 表示我的缩放点占整个集合大小的百分比。例如,如果我计划放大 (0.5,0.3),其中我的 mandelbrot 集是 2X2,那么 ratioX = 0.5/2 等等

标签: 3d mandelbrot heightmap


【解决方案1】:

是的,如果可以的话,您应该使用double 而不是float

浮点数只有 24 位尾数,当以精度限制的值反复乘以产生的额外位时,就会丢失。

FWIW,我的 WebGL mandelbrot 生成器(由于 WebGL 限制为 float)确实管理了大约 5000 倍的缩放。

【讨论】:

    【解决方案2】:

    感谢您提供您的代码! (+1 让事情变得清晰并包含所有相关信息的问题)。

    这表明您的缩放理论是正确的。在每一步,xrangeyrange 将按一个常数因子 (0.975?) 缩放,并且窗口将向 foundPointOnHost 移动,在窗口中保持相同的相对位置(ratioXratioY) .这绝对是变焦背后的正确理论。但在实践中,由于浮点运算的工作方式,您实现缩放的方式会迅速累积舍入误差。

    我的经验法则:

    • 每次乘或除两个浮点数时,都有机会引入错误,其大小是结果的最后一位 ;
    • 但是每次您加或减两个浮点数时,您都有机会引入一个错误,其大小是的最后一位最大的操作数。

    工作示例。假设您正在放大 (0.5,0.3),并且您已经放大,所以 xrangeyrange 大约是 0.001。假设您正在使用浮点数(23 位,精度约为 7 位小数)。在您的代码中,当您减去两个 x 值以重新计算 xrange 时,您将减去两个都接近 0.5 的数字,这意味着您在 xrange 中的错误高达 0.0000001 - 小数点后七位0.5 - 由于结果约为 0.001,因此您的 xrange 仅精确到小数点后四位。然后你缩放、比率,并将xrange 添加回窗口的边缘(现在大约是 0.00025),这又是大约 0.5,所以算术运算也只能精确到 0.0000001,并且窗口边缘本身与先前的调用不准确。显然,如果您使用双打,情况会更好,但同样,您的 xrange 每次循环都会丢失精度;当您达到 x6 缩放级别时,您可能已经失去了一切。

    然后,“技巧”是减少加法和减法的数量(目前,您在每个缩放步骤中执行 6 次),并确保您的错误不会在每次迭代中累积。我建议如下:保留xrangeyrange,并重新计算每一步的边缘:(ratioXratioY 是不变的,您可能需要确定哪一个是ratio这是1-ratio :)

    xrange *= 0.975;
    xld = foundPointOnHost.x - ratioX * xrange;
    xru = foundPointOnHost.x + (1-ratioX) * xrange;
    

    y 也是如此。更好的是,计算xrange 使用本身不会在每次乘法时累积错误的操作:

    // xrange = INITIAL_RANGE * SCALE_FACTOR^frame_number
    xrange = exp ( log(INITIAL_RANGE) + frame_number*log(SCALE_FACTOR) );
    

    【讨论】:

    • 很棒的评论!我还有 2 个小问题要问你。缩放深度取决于哪些变量?我的集合的大小(以像素为单位)?或者我预成型的集合中的每个点有多少次迭代?第二个问题是如何定义缩放深度?在我的程序中,该集合被定义为一个矩形,我决定计算矩形每个边缘的长度并最终执行以下操作:zoom = (OriginalEdge1 * OriginalEdg2) / (NewEdge1*NewEdge2)。但是,如果您放大到其中一个去核器并且 1 个边缘比第二个增加得更快,则会产生错误的结果
    • 您的像素或迭代计数不应进入任何这些计算,它们仅用于绘图输出 - 缩放代码应仅计算每一帧的矩形。您的开始和结束矩形需要具有相同的纵横比,因此您的缩放比例为OriginalEdge1/NewEdge1 == OriginalEdge2/NewEdge2。即使您缩放到一个角落(在foundPointOnHost 中),只要您的xrangeyrange 以相同的速率缩放,并且您的foundPointOnHost 在窗口中保持相同的比例,您就可以了。
    • 嗯,这就是我正在做的......有点......但我不可能获得 X6 的最大缩放......我只能看到缩放直到第二个 mandelbrot 集。我的意思是当主要设置被放大并且我可以看到下一个级别..之后一切变得更蓝并且我的矩形的点彼此相遇
    猜你喜欢
    • 1970-01-01
    • 2017-10-26
    • 2017-12-03
    • 1970-01-01
    • 1970-01-01
    • 2013-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多