예제 #1
0
 public void TestLongReinterpretation()
 {
     Assert.AreEqual(
         12345.67890,
         FloatHelper.ReinterpretAsDouble(FloatHelper.ReinterpretAsLong(12345.67890)),
         "Number hasn't changed after mirrored reinterpretation"
         );
 }
예제 #2
0
 public void TestIntegerReinterpretation()
 {
     Assert.AreEqual(
         12345.0f,
         FloatHelper.ReinterpretAsFloat(FloatHelper.ReinterpretAsInt(12345.0f)),
         "Number hasn't changed after mirrored reinterpretation"
         );
 }
예제 #3
0
        public void TestFloatComparison()
        {
            Assert.IsTrue(
                FloatHelper.AreAlmostEqual(0.00000001f, 0.0000000100000008f, 1),
                "Minimal difference between very small floating point numbers is considered equal"
                );
            Assert.IsFalse(
                FloatHelper.AreAlmostEqual(0.00000001f, 0.0000000100000017f, 1),
                "Larger difference between very small floating point numbers is not considered equal"
                );

            Assert.IsTrue(
                FloatHelper.AreAlmostEqual(1000000.00f, 1000000.06f, 1),
                "Minimal difference between very large floating point numbers is considered equal"
                );
            Assert.IsFalse(
                FloatHelper.AreAlmostEqual(1000000.00f, 1000000.13f, 1),
                "Larger difference between very large floating point numbers is not considered equal"
                );
        }
예제 #4
0
        public void TestDoubleComparison()
        {
            Assert.IsTrue(
                FloatHelper.AreAlmostEqual(0.00000001, 0.000000010000000000000002, 1),
                "Minimal difference between very small double precision floating point " +
                "numbers is considered equal"
                );
            Assert.IsFalse(
                FloatHelper.AreAlmostEqual(0.00000001, 0.000000010000000000000004, 1),
                "Larger difference between very small double precision floating point " +
                "numbers is not considered equal"
                );

            Assert.IsTrue(
                FloatHelper.AreAlmostEqual(1000000.00, 1000000.0000000001, 1),
                "Minimal difference between very large double precision floating point " +
                "numbers is considered equal"
                );
            Assert.IsFalse(
                FloatHelper.AreAlmostEqual(1000000.00, 1000000.0000000002, 1),
                "Larger difference between very large double precision floating point " +
                "numbers is not considered equal"
                );
        }
예제 #5
0
        /// <summary>
        ///   Appends a double precision floating point value to a string builder
        ///   without generating garbage
        /// </summary>
        /// <param name="builder">String builder the value will be appended to</param>
        /// <param name="value">Value that will be appended to the string builder</param>
        /// <param name="decimalPlaces">Maximum number of decimal places to display</param>
        /// <returns>Whether the value was inside the algorithm's supported range</returns>
        /// <remarks>
        ///   Uses an algorithm that covers the sane range of possible values but will
        ///   fail to render extreme values, NaNs and infinity. In these cases, false
        ///   is returned and the traditional double.ToString() method can be used.
        /// </remarks>
        public static bool Append(StringBuilder builder, double value, int decimalPlaces)
        {
            const long ExponentBits       = 0x7FF; // Bit mask for the exponent bits
            const int  FractionalBitCount = 52;    // Number of bits for fractional part
            const int  ExponentBias       = 1023;  // Bias subtraced from exponent
            const int  NumericBitCount    = 63;    // Bits without sign

            // You don't need modify these as they're calculated based on
            // the constants assigned above.
            const long FractionalBits            = (2L << FractionalBitCount) - 1;
            const long HighestFractionalBit      = (1L << FractionalBitCount);
            const int  FractionalBitCountPlusOne = FractionalBitCount + 1;

            long longValue = FloatHelper.ReinterpretAsLong(value);
            long exponent  = ((longValue >> FractionalBitCount) & ExponentBits) - ExponentBias;
            long mantissa  = (longValue & FractionalBits) | HighestFractionalBit;

            long integral;
            long fractional;

            if (exponent >= 0)
            {
                if (exponent >= FractionalBitCount)
                {
                    if (exponent >= NumericBitCount)
                    {
                        return(false);
                    }
                    integral   = mantissa << (int)(exponent - FractionalBitCount);
                    fractional = 0;
                }
                else
                {
                    integral   = mantissa >> (int)(FractionalBitCount - exponent);
                    fractional = (mantissa << (int)(exponent + 1)) & FractionalBits;
                }
            }
            else
            {
                if (exponent < -FractionalBitCount)
                {
                    return(false);
                }
                integral   = 0;
                fractional = (mantissa & FractionalBits) >> -(int)(exponent + 1);
            }

            // Build the integral part
            if (longValue < 0)
            {
                builder.Append('-');
            }
            if (integral == 0)
            {
                builder.Append('0');
            }
            else
            {
                recursiveAppend(builder, integral);
            }

            if (decimalPlaces > 0)
            {
                builder.Append('.');

                // Build the fractional part
                if (fractional == 0)
                {
                    builder.Append('0');
                }
                else
                {
                    while (fractional != 0)
                    {
                        fractional *= 10;
                        long digit = (fractional >> FractionalBitCountPlusOne);
                        builder.Append(numbers[digit]);
                        fractional &= FractionalBits;

                        --decimalPlaces;
                        if (decimalPlaces == 0)
                        {
                            break;
                        }
                    }
                }
            }

            return(true);
        }