使用pygame在python中优化Mandelbrot集

55ooxyrt  于 5个月前  发布在  Python
关注(0)|答案(2)|浏览(57)

我使用了2个for循环来检查点是否在集合内,但显然这花费了太多的时间,在图本身上给出的细节较少。我如何优化代码以更快地运行,从而为图添加更多的细节?pygame原点在左上角,所以我手动设置每个点相对于中心的位置。

import math
import pygame

class Point:
    def __init__(self, x, y):
        self.x = x - 250
        self.y = y - 250

class Complex:
    def __init__(self, real, imaginary):
        self.real = real
        self.imaginary = imaginary

    def __eq__(self, other):
        if self.real == other.real:
            if self.imaginary == other.imaginary:
                return True
        return False

    def __abs__(self):
        return math.sqrt(self.real ** 2 + self.imaginary ** 2)

    def __round__(self, n=None):
        return Complex(round(self.real, 4), round(self.imaginary, 4))

    def __add__(self, other):
        return Complex(self.real + other.real, self.imaginary + other.imaginary)

    def __sub__(self, other):
        return Complex(self.real - other.real, self.imaginary - other.imaginary)

    def __mul__(self, other):
        return Complex((self.real * other.real) - (self.imaginary * other.imaginary),
                       (self.real * other.imaginary) + (self.imaginary * other.real))

def zheta(z, c):
    return round((z * z) + c, 3)

def mandelbrotNumber(num):
    z0 = Complex(0, 0)
    c = num
    checkList = [Complex(0, 0)]
    for i in range(10):
        z = zheta(z0, c)
        if abs(z) > 2:
            return False
        if z in checkList:
            return True
        checkList.append(z)
        z0 = z
    return True

def plotPoint(x, y):
    color = (0, 0, 0)
    position = (x, y)
    pygame.draw.circle(screen, color, position, 2)

pygame.init()
screen = pygame.display.set_mode((500, 500))
running = True
startPosX = (0, 250)
endPosX = (500, 250)
startPosY = (250, 0)
endPosY = (250, 500)

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    screen.fill("white")
    for i in range(-200, 200):
        for j in range(-200, 200):
            number = Complex(i / 100, j / 100)
            if mandelbrotNumber(number):
                plotPoint((number.real*100) + 300, (number.imaginary*100) + 250)

    pygame.display.flip()
pygame.quit()

字符串

esyap4oy

esyap4oy1#

如何优化代码以使其运行得更快
1.使用Python内置的复杂类型。
1.去掉四舍五入,那只是不必要的额外步骤。
1.放弃checkList,因为完全相等是不可能的,不值得付出努力。
1.与其为每个像素画一个圆,不如在内存中构建一个光栅图像(pygame文档建议称之为Surface),在其上设置像素,然后在一个绘制操作中将整个图像绘制到应用程序窗口。

x33g5p2x

x33g5p2x2#

1.优化计算

Python有一个内置的类complex,它应该更快,因为它是在C中内部实现的,但我猜你实现这个类是为了练习。
算法本身可以自行改进-请参阅@MvG列出的内容,但您可以做更多事情来提高速度-计算数字的平方根是一个相当慢的操作,x**2 + y**2 > 4将与sqrt(x**2 + y**2) > 2一样好,但会避免不必要的平方根。有更多的优化,让减少乘法的数量(比sqrt()的操作成本低,但仍然需要一点)。Wikipedia文章有一节专门介绍优化mandelbrot集绘制算法,请参阅此。
太慢了?有一些高级库可以帮助加速操作,numpy允许您“一次”对多个值进行操作,但在这里它不是很有用(没有简单的方法可以避免对已经转义的点进行不必要的操作)。更有用的库是numba-它是python子集的jit编译器,它让你编写代码的速度与编译语言相当。
如果你真的想给予一切来提高速度,那么应该使用第三方库来提高性能,但这绝对不是一个初学者友好的解决方案。

2.优化绘图

画圆-这是一个复杂的操作,最好使用类似surface.set_at()的东西来设置所选像素的颜色。
计算Mandelbrot分形每帧不是一个好主意,你可以有一个单独的表面,你可以画一次Mandelbrot集(当你在屏幕上画,你真的只是画在表面上是链接到窗口,你可以想象表面是一些虚拟的窗口,你看不见,但你可以在他们身上画,就像你通常在窗口上做的那样)
如果你真的想使用numba,使用任何与pygame表面相关的函数在numba will reduce the speed gained for usingnumba, to avoid this, edit values from an object received from` pygame.surfarray``优化的函数中绘制它们。

3.限制

总有一些限制,我上面列出的命题(即使没有关于使用numba的命题),你应该得到一个体面的程序来绘制mandelbrot集,但事实是,如果你缩放越来越多,计算所选点是否可能属于mandelbrot集就变得越来越繁重。
还有一个问题是你想花多少时间来优化这段代码。

相关问题