Rework me on GitHub

Bugs as usual

root (Edward Gerhold)

// few days old, but...
// 2 pi continued in a few days
//
// convention:
// this.method() alters the object, if the method returns a complex number
// Complex.method(this) return a new complex object by constructor calls

function Complex(real, imag, freeze)  // freeze is to create constants on the fly
{
    // changed
    // this.re to this[0]
    // and this.im to this[1]

    "use strict";
    // could check real and imag ( the spec impl would )
    // and throw, but there is no need today
    // other methods should and will throw typeerrors and range errors
    this[0] = real ||0;
    this[1] = imag ||0;	

    this.length = 2; // let´s be array like for common js programming
    
    if (freeze) Object.freeze(this);
}

function OpenEnvironment(r, z) {
    this[0] = r;
    this[1] = z;
}

OpenEnvironment.prototype = {
    distance: function (z) {
	// return a distance for re and one for i 
	// in a new complex number with distre=Re and distim=Im
	var r = this[0];
	var z = this[1];
	var dre = z[0]-w[0];	
	var dim = z[1]-w[1];
	return new Complex(dre, dim);
    },
    inside: function (w) {
	var r = this[0];
	var d = this.distance(this[1], w);
	return ((d[0] < r)&&(d[1] < r));
    }
};


Complex.prototype = {

	relError: function (x) {
	    var xx = Math.round(x);
	    return Math.abs(x-Math.round(x))/Math.abs(x);
	},
	absError: function (x) {
	    return Math.abs(x - Math.round(x));
	},

	precision: function () {
	    
	},
	env: function (r) {
	    var env = new OpenEnvironment(r, this);
	    this.environment = env;
	},
	
	length: 2,
	
	get re () {
	    return this[0];
	},
	
	set re (v) {
	    this[0] = v;
	},
	get im () {
	    return this[1];
	},
	set im (v) {
	    this[1] = v;
	},
		
	assign: function (z) {
	    this[0]=z[0];
	    this[1]=z[1];
	},
	
	clear: function () {
	    this[0] = 0;
	    this[1] = 0;
	},
	
	add: function (z) 
	{
		if (typeof z === "number") {
			this[0] += z;
		} else {
			this[0] += z[0];
			this[1] += z[1];
		}
		return this;
	},
	sub: function (z) 
	{
		if (typeof z === "number") {
			this[0] -= z;
		} else {
			this[0] -= z[0];
			this[1] -= z[1];
		}
		return this;
	},
	multiply: function (z) {
		// multiplication for the complex body C
		if (typeof z === "number") {
		    this[0] *= z;
		    this[1] *= z;
		} else {
		    this[0] = this[0] * z[0] - this[1] * z[1];
		    this[1] = this[1] * z[0] + this[0] * z[1];
		}
		return this;
	},
	divide: function (z) 
	{
		if (typeof z === "number") {
			this[0] /= z;
			this[1] /= z;
		} else {
			var im = (this[0] * -z[1])+ (this[1] * z[0]); 
			var re = (this[0] * z[0]) - (this[1] * -z[1])
			var nom= (z[0] * z[0]) - ( z[1] * -z[1]);
			this[0] = re / nom;
			this[1] = im / nom;
		}
		return this;
	},
	conjugate: function () 
	{
		this[1] = -this[1];
		return this;
	},
	abs: function () 
	{
		return Math.sqrt(this[1]*this[1] + this[0]*this[0]);
	},
	exp: function () 
	{   
		var ex = Math.pow(Math.E, this[0]);
		this[0] = ex * Math.cos(this[1]);
		this[1] = ex * Math.sin(this[1]);
		return this;
	},
	log: function () 
	{
		var abs = Math.sqrt(this[1]*this[1] + this[0]*this[0]);
		var log = Math.log(abs);
		
		if (this[1] <= 0) {
			this[0] = log;
			this[1] = Math.PI; 
		} 
		
		var sign = this[1] < 0 ? -1 : 1;
		this[1]=sign * Math.acos(this[0] / abs);
		this[0]=log;
		return this;
	},
	cosh: function () { return this.cos(); },
	cos: function () 
	{
		var eiz = Complex.exp(Complex.multiply(Complex.Constants.ONE_I, this));
		var emiz = Complex.exp(Complex.multiply(Complex.Constants.MINUS_ONE_I, this));
		return eiz.add(emiz).divide(Complex.Constants.TWO_RE);
	},
	sinh: function () { return this.sin(); },
	sin: function () 
	{
		var eiz = Complex.exp(Complex.multiply(Complex.Constants.ONE_I, this));
		var emiz = Complex.exp(Complex.multiply(Complex.Constants.MINUS_ONE_I, this));
		return eiz.sub(emiz).divide(Complex.Constants.TWO_I);
		
		// change thisvalue into cos, throw this numbers cos in a new object from the static methods on Complex
	},
	isZero: function () 
	{
		return (this[1] === 0) && (this[0] === 0);
	},
	isReal: function () 
	{
		return (this[1] === 0) && (this[0] === +this[0]);
	},
	isValid: function () 
	{
		// tests for nan
		return (this[1] === this[1]) && (this[0] === this[0]);
	},
	isNaN: function () 
	{
		// tests for nan
		return (this[1] !== this[1]) || (this[0] !== this[0]);
	},
	isFinite: function () 
	{
		return (Math.abs(this[0]) != Infinity) && (Math.abs(this[1]) != Infinity);
	},
	freeze: function () 
	{
		Object.freeze(this);
	},
	equals2: function (z) 
	{
		if (typeof z == "number") {
			return (this[0] === z) && this[1] == 0;
		}
		return (this[0] === z[0]) && (this[1] === z[1]);
	},	
	equals3: function (z) 
	{
		if (typeof z == "number") {
			return (Math.abs(this[0] - z) < Complex.equalsExactness) && (this[1] === 0);
		}
		return (Math.abs(this[0] - z[0]) < Complex.equalsExactness) && (Math.abs(this[1] - z[1]) < Complex.equalsExactness);
	},
	equals: function (z) {
		if (typeof z == "number") {
			return ((Math.abs(this[0] - z)/Math.abs(this[0])) <= Complex.doubleEps) && (Math.abs(this[1]) < Complex.doubleEps);
		}
		return ((Math.abs(this[0] - z[0])/Math.abs(this[0])) < Complex.doubleEps) && ((Math.abs(this[1] - z[1])/Math.abs(this[1]) < Complex.doubleEps));
	},
	clone: function () 
	{
		return new Complex(this[0], this[1]);
	},	
	toVector: function () {
		return [this[0], this[1]];
	},
	fromVector: function (v) {
		this[0] = v[0];
		this[1] = v[1];
	},
	
	toString: function () {
		return "[object Complex]";
	},
	
        converges: function (againstZ) {
    	    return (Math.abs(this[0] - againstZ[0]) < Complex.defaultConvergence) && (Math.abs(this[1] - againstZ[1]) < Complex.defaultConvergence);	
	}
};


Complex.equalsExactness = Number.MIN_VALUE*2;
Complex.eps = function (q, l)
{
    // eps(q,l):=(q/2)q^-l
    return (q/2)*Math.pow(q,-l);
};

Complex.doubleEps = Complex.eps(10, 11); // 10 or 2


Complex.TWO_PI = Math.PI*2;

Complex.fact = function (n) 
{
	// for series. calculation each n only once
	var product;
	if (product = Complex._factmem[n]) return product;
	product = n;
	var m = n;
	if (n < 1) return 1;
	while (n > 1) {
	    n--;
	    product *= n;
	}
	return Complex._factmem[m] = product;
};
Complex._factmem = Object.create(null);


Complex.add = function (z1, z2) {
	if (typeof z2 === "number") {
	return new Complex(z1[0]+z2, z1[1]);
	}
	return new Complex(z1[0]+z2[0], z1[1]+z2[1]);
};

Complex.sub = function (z1, z2) 
{
	if (typeof z2 === "number") {
	return new Complex(z1[0]-z2, z1[1]);
	}
	return new Complex(z1[0]-z2[0], z1[1]-z2[1]);
};


Complex.multiply = function (z1, z2) {
	if (typeof z2 === "number") {
	    return new Complex(z1[0]*z2, z1[1]*z2);
	}
	return new Complex(z1[0]*z2[0] - z1[1]*z2[1], 
			   z1[1]*z2[0] + z1[0]*z2[1]);
};

Complex.divide = function (z1, z2) {
	if (typeof z2 === "number") {
	return new Complex(z1[0]/z2, z1[1]/z2);
	}
	var re =  z1[0] * z2[0];     
	var im1 = z1[0] * -z2[1];  
	var im2 = z1[1] * z2[0]; 
	var isq = z1[1] * -z2[1]; 
	var den_re = re-isq;
	var den_im = im1+im2;
	re =  z2[0] * z2[0];
	isq = z2[1] * -z2[1];
	var nom = re-isq;  
	return new Complex(den_re/nom, den_im/nom); 
};



Complex.conjugate = function (c) 
{
	return new Complex(c[0], -c[1]);
};

Complex.arg = function (z) 
{
	if (z[1] === 0 || z[1] === -Infinity) { 
	// this range is not correct, but the main sense of arg is
		return Math.PI;
	} 
	
	return (z[1] < 0? -1:1) * Math.acos(z[0] / abs);
};

Complex.log = function (z) 
{
	var abs = Math.sqrt(z[1]*z[1] + z[0]*z[0]);
	var log = Math.log(abs);
	if (z[1] <= 0) {
		return new Complex(log, Math.PI);
	} 
	return new Complex(log, ((z[1] < 0) ? -1:1) * Math.acos(z[0] / abs));
};

Complex.abs = function (z) {    
	// euclidean norm is equal
	return Math.sqrt(z[1]*z[1] + z[0]*z[0]);
};

Complex.exp = function (z) {
	if (typeof z === "number") z = new Complex(z, 0);
	var ex = Math.exp(z[0]);
	// var ex = Math.pow(Math.E, z[0]);
	return new Complex(ex * Math.cos(z[1]), ex * Math.sin(z[1]));
};

Complex.exp2 = function (phi) {
	phi = phi % (Math.PI *2); 
	// prolly neccessary otherwhere, too. Here it is.
	return new Complex(Math.cos(phi), Math.sin(phi));
};



// z go to zzero, maybe by 2^-53 differenc
// i already have a algorithmic limit theory, but no impl of (yet)
Complex.limit = function (z, z0, f) {
	// returns f´(z0) or gives a limit
	var nominator = Complex.sub(z, z0);
	var denominator = Complex.sub(f(z), f(z0));
	if (Complex.isZero(nominator)) return;
	return Complex.divide(denominator, nominator);
};


Complex.cube = function (z) {
	return new Complex(z[0]*z[0]*z[0] - 3*z[0]*z[1]*z[1], 3*z[0]*z[0]*z[1] - z[1]*z[1]*z[1]);
};

Complex.square = function (z) {
	return new Complex(z[0]*z[0] - z[1]*z[1], z[0]*z[1] + z[0]*z[1]);
};

Complex.sin = function (z) 
{
	var eiz = Complex.exp(Complex.multiply(Complex.Constants.ONE_I, z));		
	var emiz = Complex.exp(Complex.multiply(Complex.Constants.MINUS_ONE_I, z));
	return eiz.sub(emiz).divide(Complex.Constants.TWO_I);
};

Complex.cos = function (z) 
{
	var eiz = Complex.exp(Complex.multiply(Complex.Constants.ONE_I, z));
	var emiz = Complex.exp(Complex.multiply(Complex.Constants.MINUS_ONE_I, z));
	return eiz.add(emiz).divide(Complex.Constants.TWO_RE);
};
	
Complex.pow = function(z, k)    
{
	// raise z to kth power
	
	// oh, i forgot first
	// this only takes integers, no 0.5 = sqrt or such.
	if (k == 0) {
		return new Complex(1, 0);
	} 
		var result;
	if (k > 0) {
		result = Complex.clone(z);
		while (k > 1) {
			result.multiply(z);
			k--;
		}
		return result;
	} 
	if (k < 0) {
		result = new Complex(1,0);
		while (k < 0) {
			result.divide(z);
			k++;
		}
		return result;
	}
};

Complex.complexDet2x2 = function (A) {
    // return ad-bc
    return Complex.multiply(A[0], A[3]).subtract(Complex.multiply(A[1],A[2]));
};

Complex.mat2 = function (a,b,c,d) {
    // for a complex typed array version the code must
    // go through replacing all [1] and [0] with [1] and [0]
    // done one afternoon. now we try vanilla js.
    
    // complex matrices have 2 fields each entry. maybe i can develop
    // for and find a place to put some idea by me. 
    return [a,b,c,d];
}

Complex.Mat2x2 = function Mat2x2(a,b,c,d) {
    "use strict";
    this[0] = a;
    this[1] = b;
    this[2] = c;
    this[3] = d;
    this.length = 4;
    
};
Complex.Mat2x2.prototype = {
    multiply: function (B) {
	// currently skipping double impl.
	var m = Complex.mat2mul(this, B);
	// temp
	for (var i = 0, j = m.length; i < j; i++) {
	    this[i] = m[i];
	}
	this.length = m.length;
	return this;
    }    
};

Complex.mat2mul = function (A,B) {

    var C = [];
    if (A.length == 4 && B.length == 2) {
	// 2x2 with 2x1
	C[0] = Complex.multiply(A[0], B[0]).add(Complex.multiply(A[2], B[1]));
	C[1] = Complex.multiply(A[1], B[0]).add(Complex.multiply(A[3], B[1]));
	C.length = 2;
	return C;
    }

    if (A.length == 4 && B.length == 4) {
	// Matrix 2x2 with 2x2
	C[0] = Complex.multiply(A[0], B[0]).add(Complex.multiply(A[2], B[2]));
	C[1] = Complex.multiply(A[0], B[1]).add(Complex.multiply(A[2], B[3]));
	C[2] = Complex.multiply(A[1], B[0]).add(Complex.multiply(A[3], B[2]));
	C[3] = Complex.multiply(A[1], B[1]).add(Complex.multiply(A[3], B[3]));
	C.length = 4;
	return C;
    }

    if (A.length == 2 && B.length == 4) {
	// 2x1 with 2x2
	// is 2x2
	C[0] = Complex.multiply(A[0], B[0]);
	C[1] = Complex.multiply(A[0], B[1]);
	C[2] = Complex.multiply(A[1], B[2]);
	C[3] = Complex.multiply(A[1], B[3]);
	C.length = 4;
	return C;
    }
    
    if (A.length == 2 && B.length == 2) {
	//this returns NO ARRAY!! just a scalar
	return Complex.multiply(A[0], B[0]).add(Complex.multiply(A[1]+B[1]));
	
	
	// return [1]?
	//C[0] = Complex.multiply(A[0], B[0]).add(Complex.multiply(A[1]+B[1]));
	//C.length = 1;
	//return C;
    }
    
};

Complex.mTransform = function (A, z) {
	// A = [a, b; c, d]
	
	if (Complex.isZero(Complex.complexDet2x2(A))) return undefined;
	
	var den = Complex.multiply(z, A[0]).add(A[1]);
	var nom = Complex.multiply(z, A[2]).add(A[3]);
	nom.multiply(Complex.conjugate(nom));
	if (nom[0] !== 0)
	return new Complex(den[0]/nom[0], den[1]/nom[0]);
};

Complex.cayleyTransform = function (z) {    
	return Complex.mTransform(
	    [ Complex.Constants.ONE_RE, Complex.Constants.MINUS_ONE_I, Complex.Constants.ONE_RE, Complex.Constants.ONE_I ], 
	    z
	);	
};

Complex.translate = function (b, z) 
{
	return Complex.add(z, b);
};

Complex.scale = function (a, z) {
	return Complex.multiply(a,z);    
};

Complex.invert = function (z) 
{
	return (new Complex(1, 0)).divide(z);
};

Complex.doubleRatio = function (z1, z2, z3, z4) {
	// "Doppelverhaeltnis" 
	// it is
	// (z1-z2) * (z3-z4) divided by
	// (z2-z3) * (z4-z1)
	return Complex.sub(z1,z2).multiply(Complex.sub(z3,z4)).divide( 
		Complex.sub(z2,z3).multiply(Complex.sub(z4,z1)) 
	);
}


/*
	Next is getting the line integrals along the border working, eh

	
*/

Complex.integrate = function (a, b, n, f) {
P	// [a,b] is the interval, n the number of rectangles
	// this summarises two integrals for the real and the imaginary part.
	
	// anyways, it´s wrong and i was about remembering $ pdx + qdy
	// but that´s not today
	
		var deltaz = (b-a)/n;
		var riemann_sum_re = 0;
		var riemann_sum_im = 0;
	for (var i = a; i <= b; i+= deltaz) {
		var z = f(new Complex(i))
		riemann_sum_re += z[0] * deltaz;
		riemann_sum_im += z[1] * deltaz;
	}
	return new Complex(riemann_sum_re, riemann_sum_im);
};

// No check if I^(S) and I_(S) are equal? 

Complex.integrate_double_check_the_rules = function (a, b, n, f) {
	// [a,b] is the interval, n the number of rectangles
	var deltaz = (b-a)/n;
	var riemann_sum = new Complex;
	for (var i = a; i <= b; i+= deltaz) {
		riemann_sum.add(Complex.multiply(f(new Complex(i)), deltaz));
	}
	return riemann_sum;
};




Complex.lineIntegral = function (a, b, f, delta)
{
    
    // absolutly wrong implementation (yet)

    
    delta = delta || 0.01; // how far i go on the arc
    
    var deltax;
    var deltay;

    var x = 0,
        y = 0, 
        lastx = 0, 
	lasty = 0;

    var sum = new Complex(0,0);
    var arc, work;
    
    for (var i = a; i <= b; i+=delta) {
	
	z = f(i);
	var x = z[0];
	var y = z[1];
	deltax = x - lastx;
	deltay = y - lasty;
	
	// not right, but it´s going into the right direction, guys
	// this from the physics work integral
	// after becoming valid it has to become a complex cauchy integral
	// currently it´s not even giving a valid result
		
	arc = Math.sqrt(deltax*deltax + deltay*deltay);
	work = Complex.multiply(z, arc);
	sum.add(work);
	
	lastx = x;
	lasty = y;
    }
    
    return sum;
};


Complex.defaultConvergence = 1e-33;
Complex.converges = function (z1, z2) {
	return (Math.abs(Math.abs(z1[0]) - Math.abs(z2[0])) < Complex.defaultConvergence) && (Math.abs(Math.abs(z1[1]) - Math.abs(z2[1])) < Complex.defaultConvergence);	
};

Complex.sequence = function (z0, k, fz) 
{
	if (!Complex.isComplexType(z0)) {
	    z0 = Complex(z0, 0);
	}
	var last;
	var zk = z0;
	var seq = [z0];
	for (var i = 1; i <= k; i++) {    
	    last = zk;
	    zk = fz(i, zk);
	    if (!Complex.isValid(zk) || Complex.isZero(zk)) break;
	    seq.push(zk);
	    //if Complex.converges(last, zk)) break;
	}
	return seq;
};

Complex.series = function (z0, k, fz) 
{
	var sum = new Complex(0,0);
	    if (!Complex.isComplexType(z0)) {
	    z0 = Complex(z0, 0);
	}
	var zk = z0;
	var seq = [z0];
	var last;
	for (var i = 1; i <= k; i++) {    
	    last = zk;
	    zk = fz(i, zk); // i is k passed into, with the last zk
	    
	    // i am missing the coefficients array or callback (fourier) here
	    if (!Complex.isValid(zk) || Complex.isZero(zk)) break;
	    sum.add(zk);
	    //if Complex.converges(zk, last)) break;
	}
	return sum;
};


Complex.sequence2 = function (z, z0, k, coeffs, callback) {
	var ak = 1;
	var zk = z0;
	var sequence = [];
	var last;
	for (var i = 0; i < k; i++) {
		if (coeffs) ak = (coeffs[i] || 0);
		else ak = 1;
		last = zk;
		zk = callback(ak, z, z0, i, zk); // next = callback(..., prev);

		if (!Complex.isValid(zk) || Complex.isZero(zk)) break;
		sequence.push(zk);
		//if Complex.converges(zk, last)) break;
	}
	return sequence;
	
};

Complex.sequence3 = function (z, z0, start, k, coeffs, callback) {
	var ak = 1;
	var zk = z0;
	var sequence = [];
	var last;
	for (var i = start; i < k; i++) {
		if (coeffs) ak = (coeffs[i] || 0);
		else ak = 1;
		last = zk;
		zk = callback(ak, z, z0, i, zk); // next = callback(..., prev);
		if (!Complex.isValid(zk) || Complex.isZero(zk)) break;
		sequence.push(zk);
		//if Complex.converges(zk, last)) break;
	}
	return sequence;
	
};


Complex.series3 = function (z, z0, start, k, coeffs, callback) {
	var ak = 1;
	var zk = z0;
	var sum = new Complex;
	var last;
	for (var i = start; i < k; i++) {
		if (coeffs) ak = (coeffs[i] || 0);
		else ak = 1;
		last = zk;
		zk = callback(ak, z, z0, i, zk); 
		if (!Complex.isValid(zk) || Complex.isZero(zk)) break;
		sum.add(zk);
		//if Complex.converges(zk, last)) break;
	}
	return sum;
};



Complex.power_series = function (z, z0, k, coeffs) 
{
	// ordinary power series
	var sum = new Complex;
	var zminusz0 = Complex.sub(z,z0);
	Complex.sequence2(z, z0, k, coeffs, function (ak, z, z0, k, zk) {
		zk = Complex.multiply(Complex.pow(zminusz0, k), ak); // this is the (ak*(z-z0)^k)k elem N.
		sum.add(zk);
		return zk;
	});
	return sum;
}

Complex.power_sequence = function (z, z0, k, coeffs) 
{
	var zminusz0 = Complex.sub(z,z0);
	return Complex.sequence2(z, z0, k, coeffs, function (ak, z, z0, k, zk) {
		return Complex.multiply(Complex.pow(zminusz0, k), ak);
	});
}


Complex.laurent_series = function ()
{
	// got my book closed
	var sum = new Complex;
	var zminusz0 = Complex.sub(z,z0);
	Complex.sequence3(z, z0,  Number.MIN_VALUE, Number.MAX_VALUE, coeffs, function (ak, z, z0, k, zk) {
		zk = Complex.multiply(Complex.pow(zminusz0, k), ak); // this is the (ak*(z-z0)^k)k elem N.
		sum.add(zk);
		return zk;
	});
	return sum;
};


Complex.fourier_series = function (f, n, t) 
{
	return Complex.se
}


Complex.exp_series = function (z) 
{
	var k = 0;
	var sum = new Complex(0,0);
	while (k < Infinity) {
		var zk = Complex.pow(z, k);
		zk.divide(Complex.fact(k));
		// here is better convergence testing by error estimation necc. i am taking class for, just begun
		if (Complex.isZero(zk) || !Complex.isValid(zk)) return sum;
		sum.add(zk);
		k++;
	}
	return sum;
};
Complex.sin_series = function (z) 
{
	var k = 0;
	var sum = new Complex(0,0);
	while (k < Infinity) {
		var sign = Math.pow(-1, k);
		var zk = Complex.pow(z, 2*k+1);
		zk[0] *= sign;
		zk[1] *= sign;
		zk.divide(Complex.fact(2*k+1));
		if (Complex.isZero(zk) || !Complex.isValid(zk)) return sum;
		sum.add(zk);
		k++;
	}
	return sum;
};

Complex.cos_series = function (z) 
{
	var last = 0;
	var k = 0;
	var sum = new Complex(0,0);
	while (k < Infinity) {
		var sign = Math.pow(-1, k);
		var zk = Complex.pow(z, 2*k);
		zk[0] *= sign;
		zk[1] *= sign;
		zk.divide(Complex.fact(2*k));
		if (last && Complex.converges(zk, last)) return sum;
		//if (Complex.isZero(zk) || !Complex.isValid(zk)) return sum;
		sum.add(zk);
		last = zk;
		k++;
	}
	return sum;
};



Complex.isConjugate = function (a,b) 
{
	return (a[0] === b[0]) && (a[1] === -b[1]);
};

Complex.isReal = function (z) 
{
	return z[1]===0;
};

Complex.isZero = function (z) 
{
	return z[0]===0&&z[1]===0;
};

Complex.isValid = function (z) 
{
	return (z[0] === z[0]) && (z[1] === z[1]);
};

Complex.isComplexType = function (z) 
{
	return z instanceof Complex;
};

Complex.toComplex = function (z) 
{
	if (Array.isArray(z)) return new Complex(z[0],z[1]);
	if (typeof (+z) === "number") return new Complex(+z, 0);
	if (z instanceof Complex) return z;
	throw new TypeError("can not convert");
};

Complex.clone = function (z) 
{
	if (typeof z=="number") return new Complex(z, 0);
	return new Complex(z[0], z[1]);
};


Complex.fromVector = function (z) 
{
	return new Complex(z[0], z[1]);
};
Complex.toVector = function (z) 
{
	if (typeof z === "number") {
	return [z, 0];
	}
	return [z[0], z[1]];
};

Complex.cartesianProduct = function (I, J) 
{
	// return from cP: IxJ -> P a set of arrays of two points
	var P = [];
	for (var i = 0; i < I.length; i++) {
	for (var j = 0; j < J.length; j++) {
		P.push([I[i], J[j]]);
	}   
	}
	return P;
};


Complex.plot = function (I,f) {
	// I contains any number of points (single value)
	// f a function taking a complex number and returning a complex number
	var points = [];
	I.forEach(function (i) {
		points.push(f(new Complex(i)).toVector());
	});
	return points;
};

Complex.plot2 = function (a,b,n,f) {
	// a interval start
	// b end value
	// n number of points
	// f a function taking a number and returning a complex number
	var points = [];
	var deltaz = (b-a)/n;
	for (var i = a; i <= b; i+=deltaz) {    
	    points.push(f(i).multiply(deltaz).toVector());
	}
	return points;
};

/*
	the plotting isnt it yet

	this is before inveting a disc with a slit and some
	transformations by mTransform and the other functions


*/

Complex.print = function (c) 
{
	console.log("("+c[0]+" "+(c[1]<0 ? "":"+")+c[1]+"i)");
};

Complex.printAll = function (a) {
	a.forEach(Complex.print);
};


Complex.Constants = {	
	// creating new instances is costly,
	// these constants help doing redundant work



	ONE_RE: new Complex(1, 0, true), 
	MINUS_ONE_RE: new Complex(-1, 0, true),
	TWO_RE: new Complex(2, 0, true),
	ONE_OVER_TWO_PI_RE: (new Complex(1, 0)).divide(new Complex(Complex.TWO_PI, 0)).freeze(), // for cauchy
	ONE_I: new Complex(0,1, true), // for exp, caley xform
	MINUS_ONE_I: new Complex(0,-1,true), // for exp, caley xform
	TWO_I: new Complex(0,2,true),
	TWO_PI_I: new Complex(0, Complex.TWO_PI, true), // ..
	ONE_OVER_TWO_PI_I: (new Complex(1, 0)).divide(new Complex(0, Complex.TWO_PI)).freeze() // for cauchy
};


/****
	Making it require ready
***/
if (typeof exports !== "undefined") exports.Complex = Complex;




if (typeof window != "undefined") {

Complex.Canvas = function Canvas (context) {
	"use strict;"
	this.context = context;
};

Complex.Canvas.prototype.centerContext = function () {
	var context = this.context;
	if (context.resetTransform) context.resetTransform();
	context.translate(context.canvas.width/2, context.canvas.height/2);
};

Complex.Canvas.prototype.drawDisc = function (radius, centerx, centery) {
	var context = this.context;
	radius = radius || 1;
	var t = 0;
	var lastx = Math.cos(t) * radius;
	var lasty = Math.sin(t) * radius;
	var x, y;
	this.centerx = centerx = centerx || 0;
	this.centery = centery = centery || 0;
	context.save();
	for (t = 0; t <= Complex.TWO_PI; t+=0.01) {
		x = centerx + Math.cos(t) * radius; 
		y = centery + Math.sin(t) * radius;
		context.moveTo(lastx,lasty);
		context.lineTo(x,y);		 
		lastx = x;
		lasty = y;
	}
	context.stroke();
	contextrestore();
}
Complex.Canvas.prototype.drawPoints = function (points, color) {
	var context = this.context;
	// draw it on a canvas2drenderingcontext
	if (!points.length) throw new TypeError("got no points");
	var lastpoint = points[0];
	context.strokeStyle = color||"black";
	context.lineWidth = "2.0";
	context.save();
	context.beginPath();
	context.moveTo(lastpoint[0],lastpoint[1]);
	var point;
	for (var i = 0; i < points.length; i++) {
		point = points[i];
		context.moveTo(lastpoint[0], -(lastpoint[1]));
		context.lineTo(point[0], -(point[1]));
		lastpoint = point;		
	}
	context.stroke();
	context.closePath();
	contextrestore();
};
Complex.Canvas.WebGL = "deferred by defect notebook (no 3d left)";

Complex.Canvas.prototype.drawAxis = function (centerx, centery) {

    var context = this.context;

    centerx = centerx || this.centerx || 0;
    centery = centery || this.centery || 0;
    var xhead = centerx+context.canvas.width/4;
    var yhead = centery+context.canvas.heigth/4;
    
    context.save();
    context.beginPath();
    context.moveTo(centerx,centery);
    context.lineTo(xhead, centery);

    context.stroke();
    context.fillText("Re", xhead, centery);
    context.fill();
    contextrestore();

    context.save();
    context.moveTo(centerx, centery);
    context.lineTo(centerx, -yhead);
    context.stroke();
    context.fillText("Im", centerx, -yhead);
    context.fill();
    contextrestore();
};

}