Ejemplo n.º 1
0
    /// <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);
    }
Ejemplo n.º 2
0
    /// <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);
    }