1

enter image description here

I tried to follow formula closely, but somehow all I get is a circle. It's in mandelbrot set coordinates, I understand that much.

for(x=-50;x<50;x++){
  for(y=-50;y<50;y++){

    // Canvas pixel coordinates to -2,2
    var x2 = x * 0.04;
    var y2 = y * 0.04;

    var i = 0;
    var z = 0;
    var c = Math.sqrt( x2*x2 + y2*y2 );

    while(true) {

      if( i > 20 || z > 4.0 ) {
        break;
      }

      z = z*z + c;

      i = i + 1;
    }
  }
}

jsFiddle: https://jsfiddle.net/d4fj1n63/

Maksim
  • 357
  • 1
  • 3
  • 11
  • Can you link to which formula you tried to follow - it may make spotting your error easier. Your code doesnt look immediately like anything on the [wiki page](https://en.wikipedia.org/wiki/Mandelbrot_set) – Jamiec Jun 06 '16 at 09:06
  • @Jamiec I used this one for complex number: http://www.mathwarehouse.com/algebra/complex-number/absolute-value-complex-number.php and this algorithm for mandelbrot: https://plus.maths.org/content/computing-mandelbrot-set – Maksim Jun 06 '16 at 09:37

2 Answers2

4

You need to perform complex arithmetic.

var x3 = 0, y3 = 0, k = 0;
while (x3*x3 + y3*y3 < 16 && k++ < 20) {
   var tmp = x3*x3 - y3*y3 + x2;
   y3 = 2*x3*y3 + y2;
   x3 = tmp;
}

The formula is zk+1 = zk2 + c, with z0 = 0 or equivalently z1 = c
where c is the current position, i.e. c = x2 + iy2.
I have z = x3 + iy3 so z2 = (x3 + iy3)2 = x32 + 2⋅ix3y3 + i2y32.
With i2 = −1 this simplifies to z2 = (x32y32) + i⋅(2⋅x3y3) and to these I add c i.e. x2 and y2.

See https://jsfiddle.net/d5avqq5w/ for live demo.

Your original code discarded the angle information in the z = Math.sqrt( x2*x2 + y2*y2 ) step, since x2 and y2 were not used after that point. Therefore the resulting color had to be independent of the angle, i.e. composed of concentric circles.

The page you gave as a reference deals with the absolute value of complex numbers. But the iteration step of the Mandelbrot formula should operate on the complex numbers as they are, not on any absolute values of complex numbers, so following that formula here is inappropriate.

There is one valid application of an absolute value, and that is when deciding whether or not to terminate the loop (i.e. to detect divergence). The other page you referenced just writes about

The modulus (length) of zn exceeds a given value.

without actually giving the threshold explicitely. I've used a threshold of 4, but I avoided the square root by testing whether the square of the length of z exceeds 16. That's where the x3*x3 + y3*y3 < 16 in my code comes from. It is more common to use 2 as the threshold (i.e. 4 for the squared test), but I felt that using 4 would be closer to the code you had, i.e. better suited to highlight the distinction between comparing the absolute value and comparing its square. Using 4 instead of 2 may cause us to detect divergence a bit later, leading to slightly higher values of the counter variable when the loop exits.

Note that Wikipedia also has some pseudocode which you might have used as the starting point, along with an explanation how the real-valued arithmetic in the code relates to the complex-valued arithmetic in the rest of the article.

MvG
  • 57,380
  • 22
  • 148
  • 276
2

You made a mathematical mistake .C,Z are complex number but you treat them as real.

I've made a minimal correction to your code so it worked as intended.

var canvas = $('canvas');
var ctx = canvas[0].getContext('2d');

for(x=-50;x<50;x++){
    for(y=-50;y<50;y++){

    var x2 = x * 0.04;
    var y2 = y * 0.04;

    var i = 0;
    var z = 0;
    //c - complex number. so c = x2+i*y2, where i^2 =-1 
    //var c = Math.sqrt( x2*x2 + y2*y2 );
    var xi= x2;
    var yi=y2;

    while(true) {


      if( i > 50 || xi*xi+yi*yi > 4.0 ) {
        break;
      }

      // z - complex number, so on every step we should calculate real and imaginary parts
      //z^2 = (x^2-y^2)+i*(2*x*y), i^2 =-1
      var tmp = xi*xi - yi*yi+x2;
      yi = 2*xi*yi+y2;
      xi = tmp;
      i = i + 1;
    }

    var color = parseInt(15/21*i).toString(16);
    ctx.fillStyle = '#'+color+color+color;

    ctx.fillRect((x+50)*2,(y+50)*2,2,2);
  }
}

jsFiddle enter image description here

Jamiec
  • 133,658
  • 13
  • 134
  • 193
vsenik
  • 518
  • 5
  • 12