Sto cercando di imparare Lisp/Scheme e ho provato a implementare una versione molto semplice del mandelbrot impostato per ottenere pratica. Il problema che ho riscontrato è che il codice funziona molto, molto lentamente. All'inizio pensavo fosse perché stavo usando la ricorsione anziché i cicli imperiali, ma ho provato a riscrivere più o meno lo stesso codice (ricorsione inclusa) in python (che non ha nemmeno l'ottimizzazione del tail-call), e ha funzionato molto liscioL'implementazione del set di Mandelbrot in Scheme è molto lenta
Quindi mi chiedo se c'è qualcosa di ovvio che mi manca nel mio codice e cosa potrei fare per farlo funzionare più velocemente.
Ecco lo snippet di codice in Schema (racket). Ho anche fatto più o meno la stessa cosa in SBCL e la velocità era paragonabile
#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)
(spero che il blocco di codice non è troppo clustery, era difficile mettere a nudo a qualcosa di più semplice)
Inoltre, So che Scheme e Common Lisp hanno numeri complessi, ma ho voluto testarlo usando numeri reali regolari, non penso che questo sia il motivo per cui funziona così lentamente.
Il parametro "i" della funzione del brodo è il numero di iterazioni e il parametro "n" della griglia del brufolo è anche il numero di iterazioni da utilizzare per ciascun punto. Quando l'ho impostato su un valore maggiore di 10, il codice impiega un'eternità per funzionare, il che non sembra normale. Anche l'aumento del tempo impiegato non sembra lineare, ad esempio richiede circa un secondo sulla mia macchina con n = 10 ma richiede alcuni minuti con n = 15 e non finisce nemmeno con n = 20
Quindi, cos'è che rende questo codice così lento?
Grazie in anticipo
È probabile che 'zr' e' zc' siano molto grandi? L'ho interrotto a un certo punto e 'zr' aveva oltre 4000 cifre. Poiché Scheme ha bigintegers, non si lamenterà della dimensione finché non verrà consumata tutta la memoria del programma. – Sylwester
"numeri reali"? Galleggianti? Se vuoi calcolare con numeri reali/mobili, devi assicurarti che li usi effettivamente e che anche le tue operazioni li usino. Vedo molte operazioni intere e razionali, che possono essere potenzialmente lente, ad esempio quando si usano bignum o grandi razionali. Basta tracciare o saltare le funzioni e si vedono i numeri utilizzati dalle funzioni. –
Più di 10 iterazioni? Pshaw, immagina 1000! Anche se è possibile implementare * modi veramente veloci per iterare, produrre un Mset sarà lento. Se lo si codifica semplicemente in modi base, sarà * molto * lento. È intensivo dal punto di vista computazionale, quindi forse hai bisogno di una migliore scelta del linguaggio. E non hai bisogno di complesse funzioni numeriche, hai solo bisogno di modi molto rapidi per manipolare numeri interi fissi o numeri reali FPU. –