Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save daiplusplus/ebb18d5a6804287544f397f300f7543b to your computer and use it in GitHub Desktop.
Save daiplusplus/ebb18d5a6804287544f397f300f7543b to your computer and use it in GitHub Desktop.
Generates a table that compares the output of .NET's IEEE-754 methods
// Instructions: copy-and-paste this into Linqpad 6 or later (I used Linqpad 7).
void Main()
{
List<TestResult> results = Run( includeArithmeticResults: false ).ToList().Dump();
String markdownTable = GenerateMarkdownTable( results );
Util.WithStyle( data: markdownTable, htmlStyle: "font-family: monospace;" ).Dump();
}
public static IEnumerable<TestResult> Run( Boolean includeArithmeticResults )
{
// Example literals:
yield return Test( 0f , "PositiveZero" );
yield return Test( -0f , "NegativeZero" );
yield return Test( 1f , "Unity" );
yield return Test( -1f , "-Unity" );
// yield return Test( 0.1f , "0.1f" );
// yield return Test( 0.01f , "0.01f" );
// yield return Test( 0.001f , "0.001f" ); // <-- This *isn't* subnormal... why not?
// Named constants:
// yield return Test( default(Single) , "default(Single)" );
yield return Test( Single.Epsilon , nameof(Single.Epsilon) );
yield return Test( Single.MaxValue , nameof(Single.MaxValue) );
yield return Test( Single.MinValue , nameof(Single.MinValue) );
yield return Test( Single.NaN , nameof(Single.NaN) );
yield return Test( Single.NegativeInfinity, nameof(Single.NegativeInfinity) );
yield return Test( Single.PositiveInfinity, nameof(Single.PositiveInfinity) );
if( includeArithmeticResults )
{
// Arithmetic results:
yield return Test( 1f / 0f, "1/0" );
// yield return Test( 1f / GetBig(), "1/99999999999999999999999999999999999999999f" );
}
}
private static Single GetBig() // <-- to prevent compile-time const calculations.
{
return DateTime.UtcNow.Year >= 2022 ? ( Single.MaxValue - 1 ) : 1;
}
public static class Ieee754
{
public static readonly Single Single_PositiveZero = 0f;
public static readonly Single Single_NegativeZero = -0f;
public static Boolean Single_IsZero( Single value ) => value == 0f;
public static Boolean Double_IsZero( Double value ) => value == 0d;
// https://stackoverflow.com/questions/4739795/how-can-i-test-for-negative-zero
private static readonly Int32 Single_NegativeZeroBits = BitConverter.SingleToInt32Bits( -0.0f );
private static readonly Int64 Double_NegativeZeroBits = BitConverter.DoubleToInt64Bits( -0.0d );
public static Boolean Single_IsNegativeZero( Single value ) => BitConverter.SingleToInt32Bits( value ) == Single_NegativeZeroBits;
public static Boolean Double_IsNegativeZero( Double value ) => BitConverter.DoubleToInt64Bits( value ) == Double_NegativeZeroBits;
public static Boolean Single_IsPositiveZero( Single value ) => BitConverter.SingleToInt32Bits( value ) == default(Single);
public static Boolean Double_IsPositiveZero( Double value ) => BitConverter.DoubleToInt64Bits( value ) == default(Double);
}
public static TestResult Test( Single value, String name )
{
return new TestResult( value, name )
{
IsNaN = Single.IsNaN( value ),
IsNegativeInfinity = Single.IsNegativeInfinity( value ),
IsPositiveInfinity = Single.IsPositiveInfinity( value ),
IsInfinity = Single.IsInfinity( value ), // <-- Placing this property next to
#if !LINQPAD5
IsFinite = Single.IsFinite( value ),
IsNegative = Single.IsNegative( value ),
IsNormal = Single.IsNormal( value ),
IsSubnormal = Single.IsSubnormal( value ),
#endif
IsZero = Ieee754.Single_IsZero( value ),
IsNegativeZero = Ieee754.Single_IsNegativeZero( value ),
IsPositiveZero = Ieee754.Single_IsPositiveZero( value ),
IsLtPosZero = value < Ieee754.Single_PositiveZero,
IsLtePosZero = value <= Ieee754.Single_PositiveZero,
IsLtNegZero = value < Ieee754.Single_NegativeZero,
IsLteNegZero = value <= Ieee754.Single_NegativeZero
};
}
public class TestResult
{
public TestResult( Single value, String name )
{
this.Value = value;
this.Name = name;
}
public readonly Single Value;
public readonly String Name;
public readonly String _1 = " ";
public /*readonly*/ Boolean? IsNaN; // .NET Fx 1.0+
public /*readonly*/ Boolean? IsFinite; // .NET Core 2.1+
public /*readonly*/ Boolean? IsInfinity; // .NET Fx 1.0+
public readonly String _2 = " ";
public /*readonly*/ Boolean? IsNegativeInfinity; // .NET Fx 1.0+
public /*readonly*/ Boolean? IsPositiveInfinity; // .NET Fx 1.0+
public readonly String _3 = " ";
public /*readonly*/ Boolean? IsZero; // `==` operator
public /*readonly*/ Boolean? IsNegativeZero; // BitConverter
public /*readonly*/ Boolean? IsPositiveZero; // BitConverter
public readonly String _4 = " ";
public /*readonly*/ Boolean? IsNegative; // .NET Core 2.1+
// These properties are intended to compare `value < 0f` to using `Single.IsNegative` and if things are different for NegativeZero vs. PositiveZero.
// UPDATE: The `<=` comparisons match, but I didn't expect `( -0f < 0f ) == false`.
public /*readonly*/ Boolean? IsLtPosZero; // `< 0f` operator
public /*readonly*/ Boolean? IsLtNegZero; // `< -0f` operator
public /*readonly*/ Boolean? IsLtePosZero; // `<= 0f` operator
public /*readonly*/ Boolean? IsLteNegZero; // `<= -0f` operator
public readonly String _5 = " ";
public /*readonly*/ Boolean? IsNormal; // .NET Core 2.1+
public /*readonly*/ Boolean? IsSubnormal; // .NET Core 2.1+
}
public static String GenerateMarkdownTable( List<TestResult> results )
{
// An exercise for the reader.
}
Value Name IsNaN IsFinite IsInfinity IsNegativeInfinity IsPositiveInfinity == 0 IsNegativeZero IsPositiveZero IsNegative < 0f < -0f <= 0f <= -0f IsNormal IsSubnormal
0 PositiveZero - true - - - true - true - - - true true - -
-0 NegativeZero - true - - - true true - true - - true true - -
1 Unity - true - - - - - - - - - - - true -
-1 -Unity - true - - - - - - true true true true true true -
1E-45 Epsilon - true - - - - - - - - - - - - true
3.4028235E+38 MaxValue - true - - - - - - - - - - - true -
-3.4028235E+38 MinValue - true - - - - - - true true true true true true -
NaN NaN true - - - - - - - true - - - - - -
-Infinity NegativeInfinity - - true true - - - - true true true true true - -
Infinity PositiveInfinity - - true - true - - - - - - - - - -
@daiplusplus
Copy link
Author

daiplusplus commented Apr 14, 2022

Visual form of the table (more compact, shows true vs. false with more contrast too):

image


I'm surprised that negative-zero is not considered less-than positive-zero, weird.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment