I think i'm hitting an infinite loop somewhere in my java Mandelbrot program

242 views Asked by At

I'm writing a program that draws a portion of a Mandelbrot fractal. I'm pretty sure that i'm hitting an infinite loop somewhere along the line here. It could very well be something else, but whatever is the matter, I cannot figure it out. Here is my code:

Mandelbrot.java

package edu.ycp.cs201.mandelbrot;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Scanner;

import javax.imageio.ImageIO;

public class Mandelbrot {
    private static final int HEIGHT = 600;

    private static final int WIDTH = 600;



    public static void main(String[] args) throws IOException {
        Scanner keyboard = new Scanner(System.in);
        System.out.println("Please enter coordinates of region to render:");
        System.out.print("  x1: ");
        double x1 = keyboard.nextDouble();
        System.out.print("  y1: ");
        double y1 = keyboard.nextDouble();
        System.out.print("  x2: ");
        double x2 = keyboard.nextDouble();
        System.out.print("  y2: ");
        double y2 = keyboard.nextDouble();

        System.out.print("Output filename: ");
        String fileName = keyboard.next();

        keyboard.close();

        int[][] iterCounts = new int[HEIGHT][WIDTH];
        MandelbrotTask task = new MandelbrotTask(x1, y1, x2, y2, 0, WIDTH, 0, HEIGHT, iterCounts);  
        task.run();


        // TODO: create the rendering, save it to a file
        BufferedImage bufferedImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
        Graphics g = bufferedImage.getGraphics();
        System.out.print("things are happening");
        for (int i = 0; i < WIDTH; i++)
        {
            for (int j = 0; j < HEIGHT; j++)
            {

                if (iterCounts[i][j] < 10)
                {
                g.setColor(Color.BLACK);
                g.fillRect(i,j,1,1);
                }
                else 
                    g.setColor(Color.BLUE);
                    g.fillR

ect(i,j,1,1);
            }

    }
    g.dispose();



    OutputStream os = new BufferedOutputStream(new FileOutputStream(fileName));

    try {
        ImageIO.write(bufferedImage, "PNG", os);
    } finally {
        os.close();
    }
}

Complex.java

package edu.ycp.cs201.mandelbrot;

public class Complex {
    double x;
    double y;

    // Constructor
    public Complex(double real, double imag) {
        this.x = real;
        this.y = imag;
    }

    // add given complex number to this one, returning the Complex result
    public Complex add(Complex other) {
        return new Complex((this.x + other.x), (this.y + other.y));
    }

    // multiply given complex number by this one, returning the Complex result
    public Complex multiply(Complex other) {
        double real = (this.x*other.x) - (this.y*other.y);
        double imag = (this.x*other.y) + (this.y*other.x);
        return new Complex(real, imag);
    }

    // get the magnitude of this complex number
    public double getMagnitude() {
        return Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2));
    }
}

MandelbrotTask.java

package edu.ycp.cs201.mandelbrot;


public class MandelbrotTask implements Runnable {
    private double x1, y1, x2, y2;
    private int startCol, endCol, startRow, endRow;
    private int[][] iterCounts;


    public MandelbrotTask(double x1, double y1, double x2, double y2,
                          int startCol, int endCol, int startRow, int endRow,
                          int[][] iterCounts) {
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;
        this.startCol = startCol;
        this.endCol = endCol;
        this.startRow = startRow;
        this.endRow = endRow;
        this.iterCounts = iterCounts;

    }

    public void run() {
        System.out.print("Working...");
        for (int i = startRow; i < endRow; i++) {
            for (int j = startCol; j < endCol; j++) {
                  Complex c = getComplex(i, j);
                  int iterCount = computeIterCount(c);
                  iterCounts[i][j] = iterCount;
            }
        }
        System.out.print("donarino");

    }

    // TODO: implement getComplex and computeIterCount methods

    public Complex getComplex(double i, double j)
    {
        double k ,l;

         k = ((x2 - x1)/600)*i + x1;
         l = ((y2 - y1)/600)*j + y1;
        //System.out.println(" k :" + k + " l: " + l);

        return new Complex(k,l);
    }

    public int computeIterCount(Complex c)
    {
        Complex z = new Complex(0,0);
        int count = 0;
        while (z.getMagnitude() < 2 || count <= 11)
        {
            z = z.multiply(z).add(c);
            count++;
        }
        return count;
    }
}
2

There are 2 answers

0
karatedog On BEST ANSWER

I have several suggestions.

General:

  • use only data in a function that were provided as argument (and not like refering to x1, x2 from inside getComplex() ). Both solution work but this makes the function standalone debuggable as you provide all data to the function.

Mandelbrot-wise:

  • first create a function that can calculate a single point (pixel) properly. Test it alone.
  • then organize the single pixel function into a loop (preferably iteration, so you don't have to manage the loop). Test this as well.
  • don't bother with user input until the whole thing works. Mock input data.
  • if the code is readable and works, you can begin to optimize and ask for user input.
2
Get Off My Lawn On

You could put line debugging before and after each set of for loops for example, you could do this:

System.out.println("starting for loop on line: " + Thread.currentThread().getStackTrace()[1].getLineNumber());
for (int i = 0; i < WIDTH; i++)
{
    for (int j = 0; j < HEIGHT; j++)
    {
        // Your Code is here
    }
}
System.out.println("I am at line: " + Thread.currentThread().getStackTrace()[1].getLineNumber());

When one of the outputs doesn't show you will know what isn't finishing.