示例#1
0
        /// <summary>
        /// Returns Floor(Log(2,|<paramref name="x"/>|)).
        /// Note: this is the exponent field of a double precision number.
        /// <para>If x is NaN then x is returned</para>
        /// <para>If x == ±∞ then +∞ is returned</para>
        /// <para>If x == ±0 then -∞ is returned</para>
        /// </summary>
        /// <param name="x">Argument</param>
        public static double Logb(double x)
        {
            IEEEDouble rep = new IEEEDouble(x);

            // Check for +/- Inf or NaN
            if (!rep.IsFinite) {
                if ( rep.IsInfinity )
                    return double.PositiveInfinity;
                Policies.ReportDomainError("Logb(x: {0}): NaNs not allowed", x);
                return x;
            }

            if ( x == 0 ) {
                Policies.ReportPoleError("Logb(x: {0}): Logb(0) == -∞", x);
                return double.NegativeInfinity;

            }

            int exponent = 0;
            if (rep.IsSubnormal) {
                // Multiply by 2^53 to normalize the number
                const double normalMult = (1L << IEEEDouble.MantissaBits);
                rep = new IEEEDouble(x * normalMult);
                exponent = -IEEEDouble.MantissaBits;

                Debug.Assert(!rep.IsSubnormal);
            }

            exponent += rep.ExponentValue; 
            return exponent;
        }
示例#2
0
        /// <summary>
        /// Returns <paramref name="x"/> * 2^n
        /// </summary>
        /// <param name="x">Argument</param>
        /// <param name="n">The binary exponent (2^n)</param>
        /// <returns>
        /// Returns <paramref name="x"/> * 2^n
        /// <para>If <paramref name="x"/> is NaN, returns NaN.</para> 
        /// <para>If <paramref name="x"/> is ±0 or ±∞, returns x.</para> 
        /// <para>If n is 0, returns x.</para>
        /// </returns> 
        public static double Ldexp(double x, int n)
        {
            const double toNormal = (1L << IEEEDouble.MantissaBits);
            const double fromNormal = 1.0/(1L << IEEEDouble.MantissaBits);

            // handle special cases
            if (double.IsNaN(x)) {
                Policies.ReportDomainError("Ldexp(x: {0}, n: {1}): Requires x not NaN", x, n);
                return x;
            }
            if (double.IsInfinity(x))
                return x; // +/-Inf

            if (x == 0 || n == 0)
                return x; // +/-0, x

            IEEEDouble bits = new IEEEDouble(x);
            int xExp = 0;
            if ( bits.IsSubnormal ) {
                bits = new IEEEDouble(x * toNormal);
                xExp -= IEEEDouble.MantissaBits;
            }
            xExp += bits.ExponentValue + n;

            // there will be an overflow
            if (xExp > IEEEDouble.MaxBinaryExponent) 
                return (x > 0) ? double.PositiveInfinity : double.NegativeInfinity;
            
            // cannot represent with a denorm -- underflow
            if (xExp < IEEEDouble.MinBinaryDenormExponent) 
                return (x > 0) ? 0.0 : -0.0;
            
            if (xExp >= IEEEDouble.MinBinaryExponent) {
                // in the normal range - just set the exponent to the sum
                bits.ExponentValue = xExp;
                return bits;
            }

            // We have a denormalized number

#if true
            // Use C99 definition x*2^exp
            xExp += IEEEDouble.MantissaBits;
            Debug.Assert(xExp >= IEEEDouble.MinBinaryExponent);

            bits.ExponentValue = xExp;
            return ((double)bits) * fromNormal;
#else
            // Make it compatible with MS C library - no rounding for denorms
            // kept for future reference

            int shift = IEEEDouble.MinBinaryExponent - xExp;
            Debug.Assert(shift > 0);

            // Recover the hidden mantissa bit and shift
            const Int64 impliedbit = 1L << IEEEDouble.MantissaBits; // 1.MANTISSA = 1 << 52
            Int64 mantissa = (bits.Significand | impliedbit) >> shift;
            return BitConverter.Int64BitsToDouble(bits.Sign | mantissa);
#endif
        }
示例#3
0
        /// <summary>
        /// Returns the fraction where <paramref name="x" /> == fraction * 2 ^ exponent.
        /// <para>Note: |fraction| is in [0.5,1.0) or is 0</para>
        /// <para>if x is NaN or ±∞ then x is returned and the exponent is unspecified</para>
        /// </summary>
        /// <param name="x">Argument</param>
        /// <param name="exponent">Output the exponent value</param>
        /// <returns>System.Double.</returns>
        public static double Frexp(double x, out int exponent)
        {
            exponent = 0;

            // Check for +/- Inf or NaN
            if (double.IsNaN(x)) {
                Policies.ReportDomainError("Frexp(x: {0},...): NaNs not allowed", x);
                return x;
            }

            if (double.IsInfinity(x) || x == 0 ) 
                return x; // +/-0, +/-Inf


            IEEEDouble bits = new IEEEDouble(x);
            if (bits.IsSubnormal) {
                // Multiply by 2^52 to normalize the number
                const double normalMult = (1L << IEEEDouble.MantissaBits);
                bits = new IEEEDouble(x * normalMult);
                exponent = -IEEEDouble.MantissaBits;

                Debug.Assert(!bits.IsSubnormal);
            }

            // x is normal from here on

            // must return x in [0.5,1.0) = [2^-1,2^0) 
            // so: x_exponent must = -1 while keeping the mantissa and sign the same
            exponent += bits.ExponentValue + 1; // 2^0 = 1 = 0.5 * 2^1; so increment exponent

            // replace the exponent with 2^-1 so that x is in [0.5,1.0)
            const Int64 ExpHalf = 0x3fe0000000000000;
            return BitConverter.Int64BitsToDouble( (bits & ~IEEEDouble.ExponentMask)| ExpHalf );
        }