【问题标题】:How can I make this fractal render faster in Zelle graphics?如何在 Zelle 图形中使这种分形渲染更快?
【发布时间】:2017-05-14 21:10:37
【问题描述】:

仅用 100 次迭代渲染这个 mandelbrot 集需要一个多小时,而 10,000 次迭代需要 10 小时。有没有办法让它更快:

from graphics import *

width = 700
height = 700
win = GraphWin("Mandelbrot",width,height)
spacing = 1
zoom = 0.1
xOffset = -0.171

yOffset = 0.61
win.setBackground('black')
for x in range(0,width,spacing):
    for y in range(1,height,spacing):
        a = ((x / width) * zoom) - xOffset
        b = ((y / height) * zoom) - yOffset

        pt = Point(x,y)


        n = 0
        ca = a
        cb = b
        while(n<10000):
            aa = a * a - b * b
            bb = 2 * a * b
            a = aa + ca
            b = bb + cb
            n+=1
            if(abs(a+b) > 2000):
                break
            if(n < 2000):
               pt.setFill('black')
            if(n>5000):
                pt.setFill('grey')
            if(n>1000):
                pt.setFill('white')

        pt.draw(win)

【问题讨论】:

    标签: python python-3.x fractals zelle-graphics


    【解决方案1】:

    numpy 可能是最快的方法。 有关此方法的详细信息,请参阅"How To Quickly Compute The Mandelbrot Set In Python"

    对于纯 Python,使用原生的 complex numbers 来加速循环。也可以使用abs()函数快速计算复数的大小:

    >>> def mandle(c, boundary=2.0, maxloops=10000):
            # https://en.wikipedia.org/wiki/Mandelbrot_set
            z = 0.0j
            for i in range(maxloops):
                z = z * z + c
                if abs(z) > boundary:
                    break
            return i
    
    >>> mandle(0.04 + 0.65j)
    21
    >>> mandle(0.04 + 0.66j)
    16
    >>> mandle(0.04 + 0.67j)
    12
    

    渲染本身不太可能是程序的慢速部分(10,000 次循环可能会使绘制点的时间相形见绌)。也就是说,如果您想加快渲染速度,通常唯一的选择是在每次调用图形库时绘制多个点。

    最后,考虑一下您是否真的希望最大迭代次数为 10,000。最多 200 次迭代可以获得良好的结果。

    【讨论】:

      【解决方案2】:

      除了@RaymondHettinger 建议的复数之外,我们还可以在 Zelle 图形方面做几件事来加快速度。首先是不要使用Point(),它的开销太大。 win 实例本身具有用于位图操作的plot() 方法,该方法没有Point() 的开销,即不能取消绘制它,不能移动它。

      第二个是关闭自动刷新并在每列上执行我们自己的屏幕刷新。最后,简单地避免做任何你不需要的计算——例如ca 可以在外部循环中计算,而不是内部循环。颜色可以在最内层循环之外计算,等等。

      这是我上面的返工——对 70 x 70 图像计时,它比原始代码快 7 倍:

      from graphics import *
      
      spacing = 1
      zoom = 0.1
      
      xOffset, yOffset = -0.171, 0.61
      
      width, height = 700, 700
      
      win = GraphWin('Mandelbrot', width, height, autoflush=False)
      
      win.setBackground('black')
      
      xzoom, yzoom = zoom / width, zoom / height
      
      for real in range(0, width, spacing):
      
          ca = real * xzoom - xOffset
      
          for imaginary in range(0, height, spacing):
      
              c, z = complex(ca, imaginary * yzoom - yOffset), 0j
      
              n = 0
      
              while n < 10000:
      
                  if abs(z) > 2000:
                      break
      
                  z = z * z + c
      
                  n += 1
      
              color = 'black'
      
              if n > 5000:
                  color = 'grey'
              elif n > 1000:
                  color = 'white'
      
              if color != 'black':
                  win.plot(real, imaginary, color=color)
      
          win.flush()
      

      不是我们希望的完整数量级,但周转时间减少了 7 小时仍然很重要!

      最后,您的代码中有一个错误导致像素永远不会变灰——我已经修复了这个问题。

      【讨论】:

      • code color = int(round(n/maxIterations * 255)) pt.setFill(color_rgb(color, colour, colour)) 这个更好
      • @SamKinlochLarge,如何更好?我计时了,你的代码没有更快。 OP 的问题是关于speed,而我的回答是关于speed。至于如何选择颜色,这取决于 OP,这应该是对他的帖子的评论,而不是我的。
      • 很抱歉
      猜你喜欢
      • 2014-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-23
      • 2011-12-15
      相关资源
      最近更新 更多