public void TestLongReinterpretation() { Assert.AreEqual( 12345.67890, FloatHelper.ReinterpretAsDouble(FloatHelper.ReinterpretAsLong(12345.67890)), "Number hasn't changed after mirrored reinterpretation" ); }
public void TestIntegerReinterpretation() { Assert.AreEqual( 12345.0f, FloatHelper.ReinterpretAsFloat(FloatHelper.ReinterpretAsInt(12345.0f)), "Number hasn't changed after mirrored reinterpretation" ); }
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" ); }
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" ); }
/// <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); }