Math.cos = function(a)
{
	// Bring a into the 0 to +pi range without expensive branching.
	// Uses the symmetry that cos is even.
	a = (a + Math.PI) % (2*Math.PI);
	a = Math.abs((2*Math.PI + a) % (2*Math.PI) - Math.PI);
	
	// make b = 0 if a < pi/2 and b=1 if a > pi/2
	var b = (a-Math.PI/2) + Math.abs(a-Math.PI/2);
	b = b/(b+1e-30); // normalize b to one while avoiding divide by zero errors.
	
	// if a > pi/2 send a to pi-a, otherwise just send a to -a which has no effect
	// Using the symmetry cos(x) = -cos(pi-x) to bring a to the 0 to pi/2 range.
	a = b*Math.PI - a; 
	
	var c = 1 - 2*b; // sign of the output
	
	// Taylor expansion about 0 with a correction term in the quadratic to make cos(pi/2)=0 
	return c * (1 - a*a*(0.5000000025619951 - a*a*(1/24 - a*a*(1/720 - a*a*(1/40320 - a*a*(1/3628800 - a*a/479001600))))));
};

Math.sin = function(a)
{
	return Math.cos(a - Math.PI/2);
};

// Returns angle from -pi/2 to pi/2
Math.atan = function(a)
{
	var tanPiBy6 = 0.5773502691896257;
	var tanPiBy12 = 0.2679491924311227;
	var sign = 1;
	var inverted = false;
	var tanPiBy6Shift = 0;
	
	if (a < 0){
		// tan(x) = -tan(-x) so remove sign now and put it back at the end
		sign = -1;
		a *= -1;
	}
	
	if (a > 1)
	{
		// tan(pi/2 - x) = 1/tan(x)
		inverted = true;
		a = 1/a;
	}
	
	if (a > tanPiBy12)
	{
		// tan(x-pi/6) = (tan(x) - tan(pi/6)) / (1 + tan(pi/6)tan(x))
		tanPiBy6Shift = Math.PI/6;
		a = (a - tanPiBy6) / (1 + tanPiBy6*a);
	}
	// Now a will be in the range [-tan(pi/12), tan(pi/12)]  
	
	// Use the taylor expansion around 0 with a correction to the linear term to match the pi/12 boundary
	// atan(x) = x - x^3/3 + x^5/5 - ...
	var r = a*(1.0000000000390272 - a*a*(1/3 - a*a*(1/5 - a*a*(1/7 - a*a*(1/9 - a*a*(1/11 - a*a*(1/13 - a*a/15)))))));
	
	// shift the result back where necessary
	r += tanPiBy6Shift;
	if (inverted)
		r = Math.PI/2 - r;
	return sign * r;
};

Math.atan2 = function(y,x)
{
	// get unsigned x,y for ease of calculation, this means all angles are in the range [0, pi/2]
	var ux = Math.abs(x);
	var uy = Math.abs(y);
	// holds the result in the upper right quadrant
	var r;
	
	// Handle all edges cases to match the spec
	if (uy === 0)
	{
		r = 0;
	}
	else
	{
		if (ux === 0)
		{
			r = Math.PI / 2;
		}
		if (uy === Infinity)
		{
			if (ux === Infinity)
				r = Math.PI / 4;
			else
				r = Math.PI / 2;
		}
		else
		{
			if (ux === Infinity)
				r = 0;
			else
				r = Math.atan(uy/ux);
		}
	}
	
	// puts the result into the correct quadrant
	// 1/(-0) is the only way to determine the sign for a 0 value
	if (x < 0 || 1/x === -Infinity)
	{
		if (y < 0 || 1/y === -Infinity)
			return -Math.PI + r;
		else
			return Math.PI - r;
	}
	else
	{
		if (y < 0 || 1/y === -Infinity)
			return -r;
		else
			return r;
	}
};

Math.acos = function()
{
	error("Math.acos() does not have a synchronization safe implementation");
};

Math.asin = function()
{
	error("Math.asin() does not have a synchronization safe implementation");
};

Math.tan = function()
{
	error("Math.tan() does not have a synchronization safe implementation");
};
