我正在尝试学习Lisp/Scheme,并尝试在其中实现一个非常简单的曼德博集,以便练习。我遇到的问题是代码运行非常慢。起初,我以为是因为我使用了递归而不是命令式循环,但我尝试在Python中重新编写了几乎相同的代码(包括递归),它运行得非常顺畅。
所以我想知道我的代码中是否有明显的缺陷,以及如何使其运行更快。
以下是Scheme(Racket)中的代码片段。我也在SBCL中做了几乎相同的事情,速度是可比较的。
我希望代码块不要太杂乱,将其简化是很困难的。
此外,我知道Scheme和Common Lisp内置了复数,但我想使用普通实数进行测试,我不认为这是运行缓慢的原因。
brot函数的参数“i”是迭代次数,“brot-grid”的参数“n”也是每个点要使用的迭代次数。当我将它设置为超过10时,代码运行时间变得异常长,这似乎不正常。时间花费的增加也似乎不是线性的,例如,在我的机器上,n = 10时只需要大约一秒钟,但n = 15时需要几分钟,而n = 20时甚至无法完成。
那么,是什么让这段代码运行如此缓慢呢?
提前感谢您。
所以我想知道我的代码中是否有明显的缺陷,以及如何使其运行更快。
以下是Scheme(Racket)中的代码片段。我也在SBCL中做了几乎相同的事情,速度是可比较的。
#lang racket
(define-syntax dotimes
(syntax-rules ()
((_ (var n res) . body)
(do ((limit n)
(var 0 (+ var 1)))
((>= var limit) res)
. body))
((_ (var n) . body)
(do ((limit n)
(var 0 (+ var 1)))
((>= var limit))
. body))))
(define (print-brot zr zc)
(if (< (+ (* zr zr) (* zc zc)) 2)
(display "@")
(display ".")))
(define (brot zr zc cr cc i)
(if (= i 0)
(print-brot zr zc)
(let ((z2r (- (* zr zr) (* zc zc))) (z2c (* 2 zr zc)))
(brot (+ z2r cr) (+ z2c cc) cr cc (- i 1)))))
(define (linspace i w)
(/ (- i (/ w 2)) (/ w 4)))
(define (brot-grid w h n)
(dotimes (i w)
(dotimes (j h)
(let ((x (linspace i w)) (y (linspace j h)))
(brot 0 0 x y n)))
(newline)))
(brot-grid 40 80 20)
我希望代码块不要太杂乱,将其简化是很困难的。
此外,我知道Scheme和Common Lisp内置了复数,但我想使用普通实数进行测试,我不认为这是运行缓慢的原因。
brot函数的参数“i”是迭代次数,“brot-grid”的参数“n”也是每个点要使用的迭代次数。当我将它设置为超过10时,代码运行时间变得异常长,这似乎不正常。时间花费的增加也似乎不是线性的,例如,在我的机器上,n = 10时只需要大约一秒钟,但n = 15时需要几分钟,而n = 20时甚至无法完成。
那么,是什么让这段代码运行如此缓慢呢?
提前感谢您。
linspace
中的常数2
更改为2.0
,整个过程就可以在十分之一秒内完成。@EtienneBoulais 那是一个错误。它只是对平方进行求和而没有开根号,因此实际值应该是4
。 - Sylwester