0

So, as a beginner, I thought I would work on a horribly, awefully terrible version of the mandelbrot set project. In this pitiful case, the set is drawn with text (Shreik!) into a text file. Because I wanted some practice with some numerical coding, I have designed the worst complex number system in existance. I can't spot the problem in the code - the one that draws a band instead of a mandelbrot set. Here it is (don't look at it too long or you could die from over expossure to noob-ioactivity):

-- complex numbers, test for mandelbrot set

----------------- Complex Numbers

data C = Complex Float Float -- a + bi
    deriving Show

data Mandelbrot = Possible -- if thought to be in mandelbrot set
                | Not Integer -- this Integer is iterations before |z| > 2 in z=z^2+c
    deriving Show

complexReal :: C -> Float
complexReal (Complex n _) = n

complexImaginary :: C -> Float
complexImaginary (Complex _ n) = n

modulus :: C -> Float
modulus (Complex n m) = sqrt ((n^2) + (m^2))

argument :: C -> Float --returns in radians
argument (Complex m n)  | n < 0 && m < 0 = pi + (argument (Complex (0-m) (0-n)))
                        | m < 0 = (pi / 2) + (argument (Complex (0-m) n))
                        | n < 0 = ((3 * pi) / 2) + (argument (Complex m (0-n)))
                        | otherwise = atan (n / m)

multComplex :: C -> C -> C
multComplex (Complex m n) (Complex x y) = Complex ((m*x)-(n*y)) ((m*y)+(n*x))

addComplex :: C -> C -> C
addComplex (Complex m n) (Complex x y) = Complex (m + x) (m + y)

----------------- End Complex numbers

----------------- Mandelbrot

inMandelbrot :: C -> Mandelbrot
inMandelbrot c = inMandelbrotTest (Complex 0 0) c 0

--(z, c, i terations) with z=z^2+c, c is plotted on set map if z is bound
inMandelbrotTest :: C -> C -> Integer -> Mandelbrot 
inMandelbrotTest z c i  | (modulus z) > 2 = Not i -- too large
                        | i > 100 = Possible -- upper limit iterations
                        | otherwise = inMandelbrotTest (addComplex (multComplex z z) c) c (i+1)

possiblyInMandelbrot :: Mandelbrot -> Bool
possiblyInMandelbrot Possible = True
possiblyInMandelbrot _ = False

mandelbrotLine :: [C] -> String
mandelbrotLine [] = "\n"
mandelbrotLine (n:x) | possiblyInMandelbrot (inMandelbrot n) = "#" ++ mandelbrotLine x
mandelbrotLine (_:x) = " " ++ mandelbrotLine x

mandelbrotFeild :: [[C]] -> String
mandelbrotFeild [[]] = ""
mandelbrotFeild (n:x) = (mandelbrotLine n) ++ (mandelbrotFeild x)

-----------------End Mandelbrot

---------------- textual output

feildLine :: Float -> Float -> Float -> Float -> [C] -- start R, end R, i, increment x
feildLine s e i x   | s > e = []
                    | otherwise = [(Complex s i)] ++ feildLine (s+x) e i x

feildGenerate :: Float -> Float -> Float -> Float -> Float -> [[C]] -- start R, end R, start i, end i, increment x
feildGenerate sr er si ei x | si > ei = [[]]
                            | otherwise = [(feildLine sr er si x)] ++ (feildGenerate sr er (si+x) ei x)

l1 :: String
l1 = mandelbrotFeild (feildGenerate (-3) 3 (-3) 3 0.05)

---------------- End textual output

main = do
    writeFile "./mandelbrot.txt" (l1)

As you can see (or can't if you didn't look) there are some unused functions for my Complex numbers. Is there hope doctor?

Summary:
Why does this draw a band instead of the mandelbrot set?

AndrewC
  • 32,300
  • 7
  • 79
  • 115
bimmo
  • 385
  • 2
  • 8
  • So, what exactly are you asking about? – leftaroundabout Jul 06 '13 at 07:20
  • Why do you defame your code so much? Learning is about trying things out. Not knowing something or learning is nothing to be ashamed of. – Petr Jul 06 '13 at 08:40
  • 1
    I'd suggest you to use some existing library for complex numbers first, such as [the one in base](http://www.haskell.org/ghc/docs/latest/html/libraries/base/Data-Complex.html). This will help you focus on the Mandelbrot part and to avoid possible errors in your implementation of `Complex`. And the existing library also implements the standard numerical classes such as `Num` or `Fractional`, which makes expressions much more readable. Later you can try implementing your own version, if you wish. (Note: This question should perhaps rather belong to http://codereview.stackexchange.com/ .) – Petr Jul 06 '13 at 08:44
  • I know very well that the code is not *that* aweful. I was just trying to push the point that I know the code isn't perfect. I mean, look at the corrections given by MathematicalOrchid. Thanks all so much! – bimmo Jul 06 '13 at 22:57

1 Answers1

4

Found your bug:

addComplex :: C -> C -> C
addComplex (Complex m n) (Complex x y) = Complex (m + x) (m + y)

It's really that simple. You have a trivial typo.


Some other suggestions:

  • Use Double rather than Float. For this example, it seems to give visibly more accurate results.
  • [x] ++ y is the same thing as x : y.
  • It is traditional to write x : xs rather than x : y. This makes it clear that one is a list element, the other is a list.
  • You can import Data.Complex to get complex-number arithmetic - but of course, you are writing this code for the purpose of learning, so that's fine.
  • If you define instance Num C where..., then you would be able to write z*z + c rather than addComplex (mulComplex z z) c. It's prettier to read - if you know how to write instances yet...
  • You can't spell "field". ;-)
MathematicalOrchid
  • 61,854
  • 19
  • 123
  • 220
  • I thought it would be a typo. and 'feild' was just easier to use seeing as I used it in the definition originally. (I will use search and replace.) Thank you so much - another set of eyes always helps. I thought about trying to define a (++) function for my complex numbers, and the only thing instances have been for me are headaches when trying to find == on custom data types! – bimmo Jul 06 '13 at 22:54
  • Well, it was either going to be a bug in generating the coordinates, or a bug in the actual iteration. GHCi lets you quickly and easily check that the coordinates look OK, so... – MathematicalOrchid Jul 07 '13 at 18:34
  • therefore the iteration contained a problems! – bimmo Jul 08 '13 at 00:49