var Approx = {
	fastlog2: (function () {
		var a = new ArrayBuffer(4),
		    i = new Int32Array(a),
		    f = new Float32Array(a);

		return function fasterLog2 (number) {
			f[0] = number;
			var t = i[0] * 1.1920928955078125e-7;
			return t - 126.94269504;
		};
	}()),

	log2: (function () {
		var a = new ArrayBuffer(8),
		    i = new Int32Array(a),
		    f = new Float32Array(a);

		return function fastLog2 (number) {
			f[0] = number;
			i[1] = (i[0] & 0x007FFFFF) | 0x3f000000;

			var t = i[0] * 1.1920928955078125e-7;
			return t - 124.22551499 - 1.498030302 * f[1] - 1.72587999 / (0.3520887068 + f[1]);
		};
	}()),

	log: function fastLog (number) {
		return 0.6931471805599453 * Approx.log2(number);
	},

	log10: function fastLog10 (number) {
		return 0.30102999566398114 * Approx.log2(number);
	},

	pow2: (function () {
		var a = new ArrayBuffer(4),
		    i = new Int32Array(a),
		    f = new Float32Array(a);

		return function fastPow2 (number) {
			var offset = (number < 0) ? 1 : 0,
			    clipNumber = (number < -126) ? -126 : number,
			    w = clipNumber | 0,
			    z = clipNumber - w + offset;

			i[0] = ( (1 << 23) * (clipNumber + 121.2740575 + 27.7280233 / (4.84252568 - z) - 1.49012907 * z) );

			return f[0];
		}
	})(),

	exp: function fastExp (number) {
		return Approx.pow2(1.442695040 * number);
	},

	fastpow2: (function () {
		var a = new ArrayBuffer(4),
		    i = new Int32Array(a),
		    f = new Float32Array(a);

		return function fasterPow2 (number) {
			var clipNumber = (number < -126) ? -126 : number;

			i[0] = ( (1 << 23) * (clipNumber + 126.94269504) );

			return f[0];
		}
	}()),

	fastexp: function fasterExp (number) {
		return Approx.fastpow2(1.442695040 * number);
	},

	sinh: function fastSinH (number) {
		return 0.5 * (Approx.exp(number) - Approx.exp(-number));
	},


	fastsinh: function fasterSinH (number) {
		return 0.5 * (Approx.fastexp(number) - Approx.fastexp(-number));
	},


	cosh: function fastCosH (number) {
		return 0.5 * (Approx.exp(number) + Approx.exp(-number));
	},

	fastcosh: function fasterCosH (number) {
		return 0.5 * (Approx.fastexp(number) + Approx.fastexp(-number));
	},

	tanh: function fastTanH (number) {
		return -1.0 + 2.0 / (1.0 + Approx.exp(-2.0 * number));
	},

	fasttanh: function fasterTanH (number) {
		return -1.0 + 2.0 / (1.0 + Approx.fastexp(-2.0 * number));
	},

	pi: Math.PI,
	halfpi: Math.PI / 2,
	twopi: 2 * Math.PI,
	invtwopi: 1 / (2 * Math.PI),
	twooverpi: 2 / Math.PI,
	fouroverpi: 4 / Math.PI,
	fouroverpisq: 4 / (Math.PI * Math.PI),
	halfpiminustwopi: Math.PI / 2 - 2 * Math.PI,

	fasthalfsin: (function () {
		var q = 0.78444488374548933,
		    a = new ArrayBuffer(16),
		    i = new Int32Array(a),
		    f = new Float32Array(a);

		return function fastHalfSin (number) {
			f[0] = 0.20363937680730309;
			f[1] = 0.015124940802184233;
			f[2] = -0.0032225901625579573;
			f[3] = number;
			var sign = i[3] & 0x80000000;
			i[3] = i[3] & 0x7FFFFFFF;
			var qpprox = Approx.fouroverpi * number - Approx.fouroverpisq * number * f[3];
			var qpproxsq = qpprox * qpprox;
			i[0] |= sign;
			i[1] |= sign;
			i[2] ^= sign;
			return q * qpprox + qpproxsq * (f[0] + qpproxsq * (f[1] + qpproxsq * f[2]));
		};
	}()),

	fasterhalfsin: (function () {
		var q = 0.78444488374548933,
		    a = new ArrayBuffer(8),
		    i = new Int32Array(a),
		    f = new Float32Array(a);

		return function fasterHalfSin (number) {
			f[0] = 0.22308510060189463;
			f[1] = number;
			var sign = i[1] & 0x80000000;
			i[1] &= 0x7FFFFFFF;

			var qpprox = Approx.fouroverpi * number - Approx.fouroverpisq * number * f[1];

			i[0] |= sign;

			return qpprox * (q + f[0] * qpprox);
		}
	}()),
	
	sin: function fastSin (number) {
		var k = (number * Approx.invtwopi) | 0,
		    half = (number < 0) ? -0.5 : 0.5;

		return Approx.fasthalfsin((half + k) * Approx.twopi - number);
	},

	fastsin: function fasterSin (number) {
		var k = (number * Approx.invtwopi) | 0,
		    half = (number < 0) ? -0.5 : 0.5;

		return Approx.fasterhalfsin((half + k) * Approx.twopi - number);
	},

	fasthalfcos: function fastHalfCos (number) {
		var offset = (number > Approx.halfpi) ? Approx.halfpiminustwopi : Approx.halfpi;

		return Approx.fasthalfsin(number + offset);
	},

	fasterhalfcos: (function () {
		var p = 0.54641335845679634,
		    a = new ArrayBuffer(4),
		    i = new Int32Array(a),
		    f = new Float32Array(a);

		return function fasterHalfCos (number) {
			f[0] = number;
			i[0] &= 0x7FFFFFFF;
			var qpprox = 1.0 - Approx.twooverpi * f[0];
			return qpprox + p * qpprox * (1.0 - qpprox * qpprox);
		};
	}()),

	cos: function fastCos (number) {
		return Approx.sin(number + Approx.halfpi);
	},

	fastcos: function fasterCos (number) {
		return Approx.fastsin(number + Approx.halfpi);
	},

	fasthalftan: function fastHalfTan (number) {
		return Approx.fasthalfsin(number) / Approx.fasthalfsin(number + Approx.halfpi);
	},

	fasterhalftan: function fasterHalfTan (number) {
		return Approx.fasterhalfsin(number) / Approx.fasterhalfsin(number);
	},

	tan: function fastTan (number) {
		var k = (number * Approx.invtwopi) | 0,
		    half = (number < 0) ? -0.5 : 0.5,
		    newNumber = number - (half + k) * Approx.twopi;

		return Approx.fasthalfsin(newNumber) / Approx.fasthalfcos(newNumber);
	},

	fasttan: function fasterTan (number) {
		var k = (number * Approx.invtwopi) | 0,
		    half = (number < 0) ? -0.5 : 0.5,
		    newNumber = number - (half + k) * Approx.twopi;

		return Approx.fasterhalfsin(newNumber) / Approx.fasterhalfcos(newNumber);
	}
};