Exemple #1
0
    public static Fix32 Atan2(this Fix32 y, Fix32 x)
    {
#if USE_DOUBLES
        return(Math.Atan2(y.ToDouble(), x.ToDouble()).ToFix32());
#endif
        var yl = (int)y;
        var xl = (int)x;
        if (xl == 0)
        {
            if (yl > 0)
            {
                return(Fix32.PiOver2);
            }
            if (yl == 0)
            {
                return(Fix32.Zero);
            }
            return(Fix32.PiOver2.Neg());
        }
        Fix32 atan;
        var   z = y.Div(x);

        // Deal with overflow
        if ((int)Fix32.One.Add(C0p28.Mul(z).Mul(z)) == (int)Fix32.MaxValue)
        {
            return((int)y < 0 ? Fix32.PiOver2.Neg() : Fix32.PiOver2);
        }

        if ((int)Abs(z) < (int)Fix32.One)
        {
            atan = z.Div(Fix32.One.Add(C0p28.Mul(z).Mul(z)));
            if (xl < 0)
            {
                if (yl < 0)
                {
                    return(atan.Sub(Fix32.Pi));
                }
                return(atan.Add(Fix32.Pi));
            }
        }
        else
        {
            atan = Fix32.PiOver2.Sub(z.Div(z.Mul(z).Add(C0p28)));
            if (yl < 0)
            {
                return(atan.Sub(Fix32.Pi));
            }
        }

        return(atan);
    }
Exemple #2
0
    /// <summary>
    /// Returns a specified number raised to the specified power. Saturates
    /// </summary>
    /// <exception cref="DivideByZeroException">
    /// The base was zero, with a negative exponent
    /// </exception>
    /// <exception cref="ArgumentOutOfRangeException">
    /// The base was negative, with a non-zero exponent
    /// </exception>
    public static Fix32 Pow(this Fix32 b, Fix32 exp)
    {
#if USE_DOUBLES
        return(Math.Pow(b.ToDouble(), exp.ToDouble()).ToFix32());
#endif
        if ((int)b == (int)Fix32.One)
        {
            return(Fix32.One);
        }
        if ((int)exp == 0)
        {
            return(Fix32.One);
        }
        if ((int)b == 0)
        {
            if ((int)exp < 0)
            {
                throw new DivideByZeroException();
            }
            return(Fix32.Zero);
        }

        if (b < 0 && exp != 0)
        {
            throw new ArgumentOutOfRangeException("Non-positive value passed to Ln", "x");
        }

        return(exp.Mul(b.Log2()).Pow2());
    }
Exemple #3
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);
    }
Exemple #4
0
    /// <summary>
    /// Returns the arccos of of the specified number, calculated using Atan and Sqrt
    /// </summary>
    public static Fix32 Acos(this Fix32 x)
    {
#if USE_DOUBLES
        return((Fix64)Math.Acos((double)x));
#endif
        if ((int)x < -(int)Fix32.One || (int)x > (int)Fix32.One)
        {
            throw new ArgumentOutOfRangeException(nameof(x));
        }

        if ((int)x == 0)
        {
            return(Fix32.PiOver2);
        }

        var result = (Fix32.One.Sub(x.Mul(x))).Sqrt().Div(x).Atan();
        return((int)x < 0 ? result.Add(Fix32.Pi) : result);
    }
Exemple #5
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);
    }