Mandelbrot Set
![](/assets/2021/01/out.png)
It's time to learn a "new" language and I'm learning Go. Actually, I need to learn Go out of necessity - for some work I'm doing and I might have to teach it as well.
The best way to learn is by doing. This morning I wrote a Go program to plot the Mandelbrot set. Back in the 90s when home computers had the power to compute these things effortlessly, many a night was spent implementing fractal graphics programs**. The set is the set of complex numbers c for which the function f(z) = z2 + c repeated iterated remains bounded. A complex number can be represented by its real part and its imaginary part on a 2d plane. For each c we plot a point of colour based on the number of iterations it takes for the iteration to cross a specified boundary.***
I found an old implementation I'd written in Fortran*. Writing it in Go was more of an exercise of getting use to variable declarations, loops and file layout. For example, there are no while loops, only for loops and this takes a bit of getting used to.
For the graphical output, I found nice and easy to use library gg that handles 2d graphics and outputs PNG files. The listing is below or here to download (with the Fortran too) for convenience. You will need to "go get" the gg library.
// Plot the Mandelbrot Set // // This is the Mandelbrot program based on one written in Fortran // in 1994. It still had the original date stamp on the files. //-rwxr-xr-x 1 cjep staff 2182 11 Mar 1994 mandel.for // // You will find better implementations and better explanations // package main // go get -d github.com/fogleman/gg import "github.com/fogleman/gg" func main() {// Tune these to get different pictures
// We have provided the right values
// for the traditional "turtle"
//
const sleft float64 = -2.25
const sright float64 = 0.75
const stop float64 = 1.5
const sbottom float64 = -1.5
const srealp float64 = 0
const simagp float64 = 0
const outputFile string = "out.png"
// Maximum number of iterations and max magnitude
const maxIterations int = 2000
const magLimit float64 = 10000
// Vertical Size of the image in pixels
const size int = 1280
colors := [15]string {
"800000", // Maroon
"008000", // Green
"000080", // Navy
"c0c0c0", // Silver
"ff0000", // Red
"00ff00", // Lime
"0000ff", // Blue
"808080", // Grey
"800080", // Purple
"808000", // Olive
"008080", // Teal
"ffff00", // Yellow
"ff00ff", // Magenta
"00ffff", // Cyan
"ffffff", // White
}
// Pixel size converted to our X & Y axes
var deltaX float64 = (sright - sleft)/float64(size)
var deltaY float64 = (stop - sbottom)/float64(size)
// Pixel indices and colours var pixelX int var pixelY int var color int // an index used to choose a colour XXX
var conX float64 // Converted position from pixels to floats
var conY float64
var magnitude float64
var x0 float64
var x1 float64
var y0 float64
var y1 float64
// Graphics - allowing for a wider image // dc := gg.NewContext(size+160, size) // We work through each pixel location regarded as a relative // location to our axes determined by sleft & sbottom above // // We are interested in the complex function f(z) = z^2 + c // where c is given by the pixel location. // Breaking this out into real & imaginary parts: // f(x, y) = x^2-y^2 + conX + i( 2xy + conY) // // where (conX, conY) is our "pixel" location. // For each point, we iterate through this function // starting at srealp, simagp. Here x0, y0 are set to srealp & simagp // x1, y1 take the "next value" then we past them to x0,y0 for the next // loop. // // We limit the number of iterations by maxIterations, // but also by the magnitude mod(z) = sqrt(x^2 + y^2) // - we haven't bothered to compute the square root here // // We want to plot how many iterations we go through at a given point // color is really counting the number of iterations we go through // we adjust it for 15 colours. Black (or "transparent") pixels // will occur in the middle if the iterations continue indefinitely // within the limit (we hit maxIterations) // f(z) = z^2 + c, c is our pixel location
for pixelX = 0; pixelX <= size; pixelX++ {
for pixelY = 0; pixelY<=size; pixelY++ {
conX = sleft + float64(pixelX) * deltaX
conY = sbottom + float64(pixelY) * deltaY
color = 0 // Really counting iterations
x0 = srealp
y0 = simagp
magnitude = 0.0
for magnitude <= magLimit && color <= maxIterations {
x1 = x0*x0 - y0*y0 + conX
y1 = 2*x0*y0 + conY
color++
x0 = x1
y0 = y1
magnitude = x0*x0 + y0*y0
}
// Plot
if color < maxIterations {
dc.SetHexColor(colors[(color-1) % 15])
dc.SetPixel(pixelX, pixelY) // [1]
}
}
}
dc.SavePNG(outputFile)
} // [1] in my Fortran code, I flipped the Y axis because the program // updated the screen interactively using a Fortran graphics library. // I haven't bothered here - we output a PNG once
* Yes, I'm old enough to have coded in Fortran. And yes, I'm old enough to have been taught it at University. We were forward thinking and learnt Fortran90.
**We had fewer television channels in those days.
***You will find both better explanations and better examples of code on other web sites :-)