问题
This takes over an hour to render this mandelbrot set with only 100 iteration and has taken 10 hours with 10,000 iterations. Is there a way to make it faster:
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)
回答1:
The fastest way in likely with numpy. See "How To Quickly Compute The Mandelbrot Set In Python" for details on this approach.
For plain pure Python, use the native complex numbers to speed-up the loop. Also use the abs() function to quickly compute the magnitude of the complex number:
>>> 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
The rendering itself isn't likely to be the slow part of your program (the 10,000 loops can dwarf the time to plot a point). That said, if you want to speed the rendering, typically the only choice is to plot multiple points per call to the graphics library.
Lastly, consider whether you really want the maximum number of iterations to be 10,000. You can get good results with a maximum of 200 iterations.
回答2:
In addition to the complex numbers suggested by @RaymondHettinger, there are several things we can do Zelle-graphics-wise to speed things up. The first is to not use Point()
, it has too much overhead. The win
instance it self has a plot()
method for bitmap manipulation that doesn't have the overhead of Point()
, i.e. can't undraw it, can't move it.
The second is to turn off autoflush and do our own screen flushes on each column. Finally, simply avoid doing any computation you don't need to -- e.g. ca
can be calculated in the outer loop, not the inner. The color can be calculated outside the innermost loop, etc.
Here's my rework as above -- timing a 70 x 70 image, it's about 7x faster than your original code:
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()
Not the full order of magnitude we might hope for, but seven hours less turn around time is still somthing!
Finally, there's a bug in your code that keeps pixels from ever coming out grey -- I've fixed that.
来源:https://stackoverflow.com/questions/43968828/how-can-i-make-this-fractal-render-faster-in-zelle-graphics