views:

345

answers:

1

I am trying to port this algorithm to clojure.

My code is

(defn calc-iterations [x y] 
  (let [c (struct complex x y)]
    (loop [z (struct complex 0 0) 
           iterations 0]
      (if (and (< 2.0 (abs z))
               (> max-iterations iterations))
        iterations
        (recur (add c (multiply z z)) (inc iterations))))))

Multiply, add and abs functions are working as they should. I have tested them with a calculator. However for the following values:

(calc-iterations 0.60703135 -0.33984375) ; should give me 2, instead I get 4
(calc-iterations -1.8421874 0.3515625 )  ; should give me 1, instead I get 3

I am checking the correct iteration numbers using another java applet that I have found on the net. it seems to be working since it produces correct output. Its iteration function is

protected int calcIterations( float x, float y ) {
    int iterations = 0;

    float xn = x, yn = y;

    while ( iterations < MAX_ITERATIONS ) {
        float xn1 = xn*xn - yn*yn;
        float yn1 = 2*xn*yn;

        xn = xn1 + x;
        yn = yn1 + y;

        float magsq = xn*xn + yn*yn;

        if ( magsq > 4 )
            break;

        iterations++;
    }

    System.out.println( x + " " + y + " " + iterations );
    return iterations;
}

Can anyone spot my error?

+4  A: 

I've spotted two differences.

  1. The Java implementation starts at z = (x, y) rather than yours which starts at (0, 0). As your recursive formula is z = z^2 + c, (0, 0)^2 + (x, y) = (x, y) so starting at (x, y) is the same as doing the first iteration. So the number of iterations will come out one less than yours because of this.
  2. The Java implementation increments the number of iterations after checking whether the result, z, is within 2 units from the origin, and doesn't increment it otherwise, whereas yours increments iterations every time. The number of iterations will come out one less than yours because of this also.

So that probably accounts for the differences in your results.

I'd argue that your implementation is more correct, because it distinguishes between the cases where |z| > 2 after one iteration (i.e. where |(x,y)| > 2), and where |z| > 2 after two iterations (i.e. where |(x^2-y^2+x, 2xy+y)| > 2), whereas the Java implementation will perform its first iteration, giving (x^2-y^2+x, 2xy+y), and exit before incrementing the number of iterations, thus not distinguishing between that case.

_jameshales