Почему изображение (Мандельброта) должно быть перекошено и обернуто?

Поэтому я просто написал небольшой фрагмент, чтобы сгенерировать фрактал Мандельброта, и представьте себе мое удивление, когда он получился уродливым и перекошенным (как вы можете видеть внизу). Я был бы признателен за точку зрения, почему это вообще могло произойти. Это опыт обучения, и я не ищу никого, кто сделает это за меня, но я как бы зашел в тупик, пытаясь отладить его. Код поколения-нарушителя:

module Mandelbrot where
import Complex
import Image

main = writeFile "mb.ppm" $ imageMB 1000

mandelbrotPixel x y = mb (x:+y) (0:+0) 0

mb c x iter | magnitude x > 2 = iter
            | iter >= 255     = 255
            | otherwise       = mb c (c+q^2) (iter+1)
    where q = x -- Mandelbrot
          -- q = (abs.realPart $ x) :+ (abs.imagPart $ x) --Burning Ship

argandPlane x0 x1 y0 y1 width height = [ (x,y) | 
        y <- [y1, y1 - dy .. y0], --traverse from
        x <- [x0, x0 + dx .. x1] ] --top-left to bottom-right
    where dx = (x1 - x0) / width
          dy = (y1 - y0) / height

drawPicture :: (a -> b -> c) -> (c -> Colour) -> [(a, b)] -> Image
drawPicture function colourFunction = map (colourFunction . uncurry function)

imageMB s = createPPM s s
        $ drawPicture mandelbrotPixel (replicate 3)
        $ argandPlane (-1.8) (-1.7) (0.02) 0.055 s' s'
    where s' = fromIntegral s

И код изображения (в котором я достаточно уверен):

module Image where

type Colour = [Int]
type Image = [Colour]

createPPM :: Int -> Int -> Image -> String
createPPM w h i = concat ["P3 ", show w, " ", show h, " 255\n",
    unlines.map (unwords.map show) $ i]

Уродливая штука с перекосом Мандель


person Community    schedule 02.06.2010    source источник
comment
Вы хотели добавить ссылку на файл изображения?   -  person jchl    schedule 02.06.2010
comment
Мой взгляд на Мандельброта: gist.github.com/291074   -  person jrockway    schedule 03.06.2010


Ответы (2)


Ну, изображение перекошено из-за неправильных размеров, но это очевидно. Вы указываете размер изображения, а затем выдаете список пикселей, но где-то с неправильным количеством пикселей в строке.

В частности, обратите внимание, что изображение переворачивается почти ровно один раз: другими словами, skew per line * height of the image = width of the image. Поскольку изображение квадратное, это означает, что вы генерируете дополнительный пиксель на строку — старая добрая ошибка «отклонение на один».

Очевидное место, где это может произойти, — это когда вы генерируете координаты для итерации. Давайте попробуем небольшой набор и посмотрим, что он нам даст:

> length $ argandPlane (-2.5) (-2) 1.5 2 10 10
121
> 10 ^ 2
100
> 11 ^ 2
121

И так. Я подозреваю, что ошибка связана с тем, что вы вычисляете приращение как реальное расстояние, деленное на размер пикселя, что дает правильное количество интервалов, но дополнительную точку. Рассмотрим интервал от 0,0 до 1,0. Используя ваш расчет с шириной 4, мы получаем:

> let x0 = 0.0
> let x1 = 1.0
> let width = 4.0
> let dx = (x1 - x0) / width
> dx
0.25
> let xs = [x0, x0 + dx .. x1]
> xs
[0.0, 0.25, 0.5, 0.75, 1.0]
> length xs
5

Итак, чтобы получить правильное количество точек, просто уменьшите размер на 1 при генерации координат.

person C. A. McCann    schedule 02.06.2010
comment
Не мог просить лучшего ответа. Большое спасибо, сэр. - person ; 02.06.2010
comment
Конечно, использование (width-1) имеет гораздо больше смысла, изначально после прочтения вашего ответа я просто использовал хвост - person ; 02.06.2010
comment
Да, и если кому интересно, для этой ошибки даже есть специальный термин: ошибка ограждения. - person C. A. McCann; 02.06.2010

Это обучающий опыт, и я не ищу, чтобы кто-то сделал это за меня, но я как бы зашел в тупик, пытаясь его отладить.

Я знаю, что camccann уже решил вашу проблему, но он как бы «дал вам рыбу», а «научил вас ловить рыбу» мог бы быть более полезным.

Итак, я поделюсь тем, что, по моему мнению, может быть полезным способом достижения решения.

Итак, ваше изображение Мандельброта искажено. Некоторые вероятные возможные причины:

  • У вас ошибка в формуле Мандельброта.
  • У вас есть ошибка при представлении/сохранении изображения

Вы можете провести эксперимент, чтобы узнать, применимо какое-либо из приведенных выше объяснений или нет. Таким экспериментом может быть, например, рисование тривиальных изображений, скажем, горизонтальных и вертикальных линий.

После этого эксперимента вы увидите, что ваши вертикальные линии не такие вертикальные. Возвращаясь к вероятным возможным причинам, ясно, что у вас есть ошибка в представлении/сохранении вашего изображения, и это все объясняет. Возможно, у вас все еще есть ошибка в формуле Мандельброта, но, скорее всего, ее нет, и сейчас это не имеет отношения к рассматриваемой проблеме.

Теперь вам следует подумать, какая ошибка сохранения изображения приведет к тому, что вертикальные линии станут диагональными. Если идея не появится, вы можете делать свой простой пример все меньше и меньше, пока результат PPM не станет достаточно маленьким, чтобы вы могли проверить его вручную. Тогда вы обязательно поймаете ошибку.

person yairchu    schedule 02.06.2010
comment
Я попытался, по крайней мере, рассказать о решении примерно в той последовательности, которой я следовал, чтобы добраться до него сам, но торопился и не изложил его так подробно, как вы, - спасибо за это. В частности, отметив один дополнительный пиксель в строке, я сузил его до генерации координат, а фрагмент GHCi был экспериментом для проверки гипотезы. - person C. A. McCann; 02.06.2010
comment
Большое спасибо, я буду иметь в виду эти вещи в следующий раз, когда я застрял. Между вашим ответом и ответом camccann я думаю, что получил все, что мог желать. - person ; 03.06.2010