Próbuję nauczyć się Lisp/Scheme i próbowałem wdrożyć bardzo prostą wersję zestawu mandelbrot, aby uzyskać praktykę. Problemem, który napotkałem, jest to, że kod działa bardzo, bardzo wolno. Na początku myślałem, że to dlatego, że używałem rekursji zamiast imperatywnych pętli, ale próbowałem przepisać mniej więcej ten sam kod (rekurencję) w pythonie (który nie miał nawet optymalizacji wywołań) i działał bardzo gładkaImplementacja zestawu Mandelbrota w Scheme jest bardzo powolna.
Zastanawiam się, czy w moim kodzie brakuje czegoś oczywistego i co mogę zrobić, aby działał szybciej.
Oto fragment kodu w Scheme (rakieta). Zrobiłem też prawie to samo w SBCL a prędkość była porównywalna
#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)
(mam nadzieję, że blok kodu nie jest zbyt clustery, trudno było się rozebrać go na coś bardziej prostego)
Również Wiem, że Scheme i Common Lisp mają wbudowane liczby zespolone, ale chciałem przetestować je przy użyciu zwykłych liczb rzeczywistych, nie sądzę, że to jest powód, dla którego działa tak wolno.
Parametr "i" funkcji brota to liczba iteracji, a parametr "n" brot-grid to również liczba iteracji, które należy zastosować dla każdego punktu. Kiedy ustawię go na więcej niż 10, kod będzie trwał wiecznie, co nie wydaje się normalne. Wydłużenie czasu również nie wydaje się być liniowe, na przykład zajmuje tylko sekundę na mojej maszynie z n = 10, ale zajmuje kilka minut z n = 15 i nie kończy się nawet n = 20
Co zatem sprawia, że ten kod działa tak wolno?
góry dzięki
Czy 'zr' i' zc' powinny być bardzo duże? Zatrzymałem go w pewnym momencie, a 'zr' miał ponad 4000 cyfr. Ponieważ Schemat ma bigintegery, nie będzie narzekał na rozmiar, dopóki cała pamięć programu nie zostanie zużyta. – Sylwester
"liczby rzeczywiste"? Pływa? Jeśli chcesz obliczyć liczby rzeczywiste/zmiennoprzecinkowe, powinieneś upewnić się, że faktycznie ich używasz i że twoje operacje również z nich korzystają. Widzę wiele operacji całkowitych i racjonalnych, które mogą być potencjalnie powolne, na przykład podczas używania bignums lub dużych racjonalnych rozwiązań. Po prostu śledź lub krok funkcji i zobaczysz numery, których używają funkcje. –
Ponad 10 iteracji? Pshaw, wyobraź sobie 1000! Nawet jeśli potrafisz zaimplementować * naprawdę zgryźliwe * sposoby iteracji, tworzenie Msetu będzie powolne. Jeśli po prostu kodujesz go w podstawowy sposób, będzie on * bardzo * wolny. Jest to intensywne obliczeniowo, więc może potrzebujesz lepszego wyboru języka. I nie potrzebujesz skomplikowanych funkcji liczbowych, potrzebujesz tylko bardzo szybkich sposobów na manipulowanie liczbami całkowitymi stałymi lub liczbami rzeczywistymi FPU. –