Я немного возился с Аккой Риккардо Террелла. NET Демонстрация фракталов (https://github.com/rikace/akkafractal), чтобы попытаться понять это. (Это здорово, между прочим)
Одна вещь, которую я попробовал как небольшая проблема для меня, состояла в том, чтобы переписать некоторые части этого более функциональным способом. У меня это работает, но это намного медленнее, чем оригинал.
Вот (более или менее) первоначальный расчет Мандельброта, адаптированный для тестирования:
let mandelbrotSet (xp : int) (yp : int) (w : int) (h :int) (width : int) (height : int)
(maxr : float) (minr : float) (maxi : float) (mini : float) : List<int> =
let mutable zx = 0.
let mutable zy = 0.
let mutable cx = 0.
let mutable cy = 0.
let mutable xjump = ((maxr - minr) / ( float width))
let yjump = ((maxi - mini) / (float height))
let mutable tempzx = 0.
let loopmax = 1000
let mutable loopgo = 0
let outputList: int list = List.empty
for x = xp to (xp + w) - 1 do
cx <- (xjump * float x) - abs(minr)
for y = yp to (yp + h) - 1 do
zx <- 0.
zy <- 0.
cy <- (yjump * float y) - abs(mini)
loopgo <- 0
while (zx * zx + zy * zy <= 4. && loopgo < loopmax) do
loopgo <- loopgo + 1
tempzx <- zx
zx <- (zx * zx) - (zy * zy) + cx
zy <- (2. * tempzx * zy) + cy
(List.append outputList [loopgo]) |> ignore
outputList
А вот моя версия с рекурсивной функцией mbCal c, выполняющей работу:
let mandelbrotSetRec (xp : int) (yp : int) (w : int) (h :int) (width : int) (height : int)
(maxr : float) (minr : float) (maxi : float) (mini : float) : List<int> =
let xjump = ((maxr - minr) / (float width))
let yjump = ((maxi - mini) / (float height))
let loopMax = 1000
let outputList: int list = List.empty
let rec mbCalc(zx:float, zy:float, cx:float, cy:float, loopCount:int) =
match (zx * zx + zy * zy), loopCount with //The square of the magnitude of z
| a,b when a > 4. || b = loopMax -> loopCount
| _ -> mbCalc((zx * zx) - (zy * zy) + cx, (2. * zx * zy) + cy, cx, cy, loopCount+1) //iteration is the next value of z^2+c
[|0..w-1|] //For each x...
|> Array.map (fun x -> let cx = (xjump * float (x+xp) - abs(minr))
[|0..h-1|] ///and for each y...
|> Array.map (fun y -> let cy = (yjump * float (y+yp) - abs(mini))
let mbVal = mbCalc(0., 0., cx, cy,0) //Calculate the number of iterations to convergence (recursively)
List.append outputList [mbVal]))|>ignore
outputList
Это просто следовало ожидать, бессмысленно загружать Actor с нагрузкой рекурсивных вызовов, или я просто делаю что-то очень неэффективно? Любые указатели с благодарностью получены!
Если вы хотите запустить их, вот небольшой тестовый скрипт:
let xp = 1500
let yp = 1500
let w = 200
let h = 200
let width = 4000
let height = 4000
let timer1 = new System.Diagnostics.Stopwatch()
timer1.Start()
let ref = mandelbrotSet xp yp w h width height 0.5 -2.5 1.5 -1.5
timer1.Stop()
let timer2 = new System.Diagnostics.Stopwatch()
timer2.Start()
let test = mandelbrotSetRec xp yp w h width height 0.5 -2.5 1.5 -1.5
timer2.Stop
timer1.ElapsedTicks;;
timer2.ElapsedTicks;;
ref = test;;
РЕДАКТИРОВАТЬ: Согласно ответу Филиппа ниже, я добавил вывод списка быстро (слишком быстро !) сделать что-то, что запускается в скрипте, не требуя импорта. Вот код для возврата изображения:
let mandelbrotSetRec (xp : int) (yp : int) (w : int) (h :int) (width : int) (height : int)
(maxr : float) (minr : float) (maxi : float) (mini : float) : Image<Rgba32> =
let img = new Image<Rgba32>(w, h)
let xjump = ((maxr - minr) / (float width))
let yjump = ((maxi - mini) / (float height))
let loopMax = 1000
//Precalculate the possible colour list
let palette = List.append ([0..loopMax - 1] |> List.map(fun c -> Rgba32(byte(c % 32 * 7), byte(c % 128 * 2), byte(c % 16 * 14)))) [Rgba32.Black]
let rec mbCalc(zx:float, zy:float, cx:float, cy:float, loopCount:int) =
match (zx * zx + zy * zy), loopCount with //The square of the magnitude of z
| a,b when a > 4. || b = loopMax -> loopCount
| _ -> mbCalc((zx * zx) - (zy * zy) + cx, (2. * zx * zy) + cy, cx, cy, loopCount+1) //iteration is the next value of z^2+c
[|0..w-1|] //For each x...
|> Array.map (fun x -> let cx = (xjump * float (x+xp) - abs(minr))
[|0..h-1|] ///and for each y...
|> Array.map (fun y -> let cy = (yjump * float (y+yp) - abs(mini))
let mbVal = mbCalc(0., 0., cx, cy,0) //Calculate the number of iterations to convergence (recursively)
img.[x,y] <- palette.[mbVal]))|>ignore
img