# include <memory>
# include <tr1/memory>
# include <stdio.h>
# include <stdlib.h>

using namespace std;
using namespace tr1;

int const RESOLUTION = 5000;

void set_fpu (unsigned int mode) {
  asm ("fldcw %0" : : "m" (*&mode));
}

namespace Test1 {
    int iters(int max_iter,double xc,double yc) {
       double x = xc;
       double y = yc;
       for(int count = 0;count<max_iter;count++) {
          if( x*x + y*y >= 4.0) { return count; }
          double tmp = x*x-y*y+xc;
          y = 2.0 * x * y + yc;
          x = tmp;
       }
       return max_iter;
    }
}

//-----------------------------------------------------------------

namespace Test2 {
    class Complex {
    public:
       Complex(double xc,double yc) : x(xc), y(yc) { }

       double norm_square() {
          return x*x+y*y;
       }

       double x;
       double y;

       auto_ptr<Complex> operator*(const Complex * other) {
         return auto_ptr<Complex>(new Complex(x*other->x-y*other->y,
                         x*other->y+y*other->x));
       }

       auto_ptr<Complex> operator+(const Complex * other) {
         return auto_ptr<Complex>(new Complex(x + other->x, y + other->y));
       }

    };

    int iters(int max_iter,double xc,double yc) {
      std::auto_ptr<Complex> c (new Complex(xc,yc));
      std::auto_ptr<Complex> z (new Complex(xc,yc));
       for(int count = 0;count<max_iter;count++) {
          if( z -> norm_square() >= 4.0 ) { return count; }
          z = *(*z * z.get ()) + c.get ();
       }

       return max_iter;
    }
}
//-----------------------------------------------------------------

namespace Test3 {
    class Complex {
    public:
       Complex(double xc,double yc) : x(xc), y(yc) { }

       double norm_square() {
          return x*x+y*y;
       }

       double x;
       double y;

       shared_ptr<Complex> operator*(const Complex * other) {
         return shared_ptr<Complex>(new Complex(x*other->x-y*other->y,
                         x*other->y+y*other->x));
       }

       shared_ptr<Complex> operator+(const Complex * other) {
         return shared_ptr<Complex>(new Complex(x + other->x, y + other->y));
       };

    };

    int iters(int max_iter,double xc,double yc) {
      shared_ptr<Complex> c (new Complex(xc,yc));
      shared_ptr<Complex> z (new Complex(xc,yc));
       for(int count = 0;count<max_iter;count++) {
          if( z -> norm_square() >= 4.0 ) { return count; }
          z = *(*z * z.get ()) + c.get ();
       }

       return max_iter;
    }
}

//-----------------------------------------------------------------

namespace Test4 {
    class Complex {
    public:
       Complex(double xc,double yc) : x(xc), y(yc) { }

       double norm_square() { return x*x+y*y; }

       double x;
       double y;

       shared_ptr<Complex> operator*(const shared_ptr<Complex> other) {
         return shared_ptr<Complex>(new Complex(x*other->x-y*other->y,
                         x*other->y+y*other->x));
       }

       shared_ptr<Complex> operator+(const shared_ptr<Complex> other) {
         return shared_ptr<Complex>(new Complex(x + other->x, y + other->y));
       };

    };

    int iters(int max_iter,double xc,double yc) {
      shared_ptr<Complex> c (new Complex(xc,yc));
      shared_ptr<Complex> z (new Complex(xc,yc));
       for(int count = 0;count<max_iter;count++) {
          if( z -> norm_square() >= 4.0 )  return count;
          z = *(*z * z) + c;
       }

       return max_iter;
    }
}

//-----------------------------------------------------------------

int run(int iters(int max_iter,double xc,double yc)) {
   clock_t const st = clock();
   int    max_val = RESOLUTION/2;
   int    min_val = -max_val;
   double mul = 2.0 / max_val;
   int    count = 0;
   for(int i=min_val;i<=max_val;i++)
   for(int j=min_val;j<=max_val;j++)
     count += iters(100,mul*i,mul*j);
   printf("result: %d\n",count);
   clock_t const en = clock();
   printf ("Time=%g\n", double (en - st) / CLOCKS_PER_SEC);
   fflush (stdout);
}

int main ()
{
  set_fpu (0x27F);
  run (Test1::iters);
  run (Test2::iters);
  run (Test3::iters);
  run (Test4::iters);
  return 0;
}

/*
result: 290068052
Time=2.19
result: 290068052
Time=41.44
result: 290068052
Time=87.41
result: 290068052
Time=83.87
*/
