/// <summary>
        /// Returns 2 raised to the specified power.
        /// Provides at least 6 decimals of accuracy.
        /// </summary>
        internal static FP Pow2(FP x)
        {
            if (x.RawValue == 0)
            {
                return(FP.One);
            }

            // Avoid negative arguments by exploiting that exp(-x) = 1/exp(x).
            bool neg = x.RawValue < 0;

            if (neg)
            {
                x = -x;
            }

            if (x == FP.One)
            {
                return(neg ? FP.One / (FP)2 : (FP)2);
            }
            if (x >= FP.Log2Max)
            {
                return(neg ? FP.One / FP.MaxValue : FP.MaxValue);
            }
            if (x <= FP.Log2Min)
            {
                return(neg ? FP.MaxValue : FP.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 = (int)Floor(x);

            // Take fractional part of exponent
            x = FP.FromRaw(x.RawValue & 0x00000000FFFFFFFF);

            var result = FP.One;
            var term   = FP.One;
            int i      = 1;

            while (term.RawValue != 0)
            {
                term    = FP.FastMul(FP.FastMul(x, term), FP.Ln2) / (FP)i;
                result += term;
                i++;
            }

            result = FP.FromRaw(result.RawValue << integerPart);
            if (neg)
            {
                result = FP.One / result;
            }

            return(result);
        }
        /// <summary>
        /// Returns the base-2 logarithm of a specified number.
        /// Provides at least 9 decimals of accuracy.
        /// </summary>
        /// <exception cref="ArgumentOutOfRangeException">
        /// The argument was non-positive
        /// </exception>
        internal static FP Log2(FP x)
        {
            if (x.RawValue <= 0)
            {
                throw new ArgumentOutOfRangeException("Non-positive value passed to Ln", "x");
            }

            // This implementation is based on Clay. S. Turner's fast binary logarithm
            // algorithm (C. S. Turner,  "A Fast Binary Logarithm Algorithm", IEEE Signal
            //     Processing Mag., pp. 124,140, Sep. 2010.)

            long b = 1U << (FP.FRACTIONAL_PLACES - 1);
            long y = 0;

            long rawX = x.RawValue;

            while (rawX < FP.ONE)
            {
                rawX <<= 1;
                y     -= FP.ONE;
            }

            while (rawX >= (FP.ONE << 1))
            {
                rawX >>= 1;
                y     += FP.ONE;
            }

            var z = FP.FromRaw(rawX);

            for (int i = 0; i < FP.FRACTIONAL_PLACES; i++)
            {
                z = FP.FastMul(z, z);
                if (z.RawValue >= (FP.ONE << 1))
                {
                    z  = FP.FromRaw(z.RawValue >> 1);
                    y += b;
                }
                b >>= 1;
            }

            return(FP.FromRaw(y));
        }
 /// <summary>
 /// Returns the natural logarithm of a specified number.
 /// Provides at least 7 decimals of accuracy.
 /// </summary>
 /// <exception cref="ArgumentOutOfRangeException">
 /// The argument was non-positive
 /// </exception>
 public static FP Ln(FP x)
 {
     return(FP.FastMul(Log2(x), FP.Ln2));
 }