/// <summary> /// Returns 2 raised to the specified power. /// </summary> public static Fix32 Pow2(this Fix32 xx) { #if USE_DOUBLES return(Math.Pow(2, x.ToDouble()).ToFix32()); #endif Fix32 x = xx; if ((int)x == 0) { return(Fix32.One); } // Avoid negative arguments by exploiting that exp(-x) = 1/exp(x). bool neg = (int)x < 0; if (neg) { x = x.Neg(); } if ((int)x == (int)Fix32.One) { return(neg ? Fix32.One.Div(Fix32.Two) : Fix32.Two); // Can be cached } if ((int)x >= (int)Fix32.Log2Max) { return(neg ? Fix32.One.Div(Fix32.MaxValue) : Fix32.MaxValue); // Can be cached } if ((int)x <= (int)Fix32.Log2Min) { return(neg ? Fix32.MaxValue : Fix32.Zero); } /* * The algorithm is based on the power series for exp(x): * http://en.wikipedia.org/wiki/Exponential_function#Formal_definition * * From term n, we get term n+1 by multiplying with x/n. * When the sum term drops to zero, we can stop summing. */ int integerPart = x.Floor().ToInt(); // Take fractional part of exponent x = (Fix32)((uint)x & FRACTIONAL_MASK); Fix32 result = Fix32.One; Fix32 term = Fix32.One; Fix32 i = Fix32.One; while ((int)term != 0) { term = x.Mul(term).Mul(Fix32.Ln2.Div(i)); result = result.Add(term); i = i.AddFast(Fix32.One); } result = (Fix32)((int)result << integerPart); if (neg) { result = Fix32.One.Div(result); } return(result); }
/// <summary> /// Returns the arctan of of the specified number, calculated using Euler series /// </summary> public static Fix32 Atan(this Fix32 zz) { #if USE_DOUBLES return(Math.Atan(z.ToDouble()).ToFix32()); #endif Fix32 z = zz; if ((int)z == 0) { return(Fix32.Zero); } // Force positive values for argument // Atan(-z) = -Atan(z). bool neg = ((int)z < 0); if (neg) { z = z.Neg(); } Fix32 result; if ((int)z == (int)Fix32.One) { result = Fix32.PiOver4; } else { bool invert = (int)z > (int)Fix32.One; if (invert) { z = Fix32.One.Div(z); } result = Fix32.One; Fix32 term = Fix32.One; Fix32 zSq = z.Mul(z); Fix32 zSq2 = zSq.Mul(Fix32.Two); Fix32 zSqPlusOne = zSq.Add(Fix32.One); Fix32 zSq12 = zSqPlusOne.Mul(Fix32.Two); Fix32 dividend = zSq2; Fix32 divisor = zSqPlusOne.Mul(Fix32.Three); for (int i = 2; i < 30; i++) { term = term.Mul(dividend.Div(divisor)); result = result.Add(term); dividend = dividend.Add(zSq2); divisor = divisor.Add(zSq12); if ((int)term == 0) { break; } } result = result.Mul(z).Div(zSqPlusOne); if (invert) { result = Fix32.PiOver2.Sub(result); } } if (neg) { result = result.Neg(); } return(result); }