An Implementation of BitConverter.SingleToInt32Bits

Back in the day when I did more Java development, I used Apache’s Commons Lang regularly to do all kinds of things like string manipulations and implementing Object.equals() and Object.hashCode().

Not too long ago, I started working more with C# and the .NET Framework and I found myself wanting some of the functionality of Commons Lang for the .NET platform. The closest thing I could find was Artur Trosin’s port of the EqualsBuilder and HashCodeBuilder classes from Commons Lang to C#. Artur’s excellent port saved me a lot of work. He even provided ported unit tests, which was a nice touch.

If I remember correctly, the port was not quite 100% complete. I had to tweak the code a bit to make all the tests pass and to make both classes work a little more like their Java counterparts. For example, I changed the implementation of EqualsBuilder.Append(double lhs, double rhs) from this:

// Original port
public EqualsBuilder Append(double lhs, double rhs)
{
  if (isEqual == false)
  {
    return this;
  }
  isEqual = (lhs == rhs);
  return this;
}

to this:

// Port, with my changes added
public EqualsBuilder Append(double lhs, double rhs)
{
  if (isEqual == false)
  {
    return this;
  }
  // java impl: 
  // return append(
  //   Double.doubleToLongBits(lhs), 
  //   Double.doubleToLongBits(rhs));
  return Append(
    BitConverter.DoubleToInt64Bits(lhs), 
    BitConverter.DoubleToInt64Bits(rhs));
}

Note that I replaced the Java method Double.doubleToLongBits() with the .NET method BitConverter.DoubleToInt64Bits(). After I made the above code changes, the ported tests for EqualsBuilder.Append(double lhs, double rhs) passed.

Next it was time to move on to fixing EqualsBuilder.Append(float lhs, float rhs). Following the pattern of the previous fix, I tried changing this:

// Original port
public EqualsBuilder Append(float lhs, float rhs)
{
  if (isEqual == false)
  {
    return this;
  }
  isEqual = (lhs == rhs);
  return this;
}

to this:

// Port, with my changes added. Does not compile! Oh no!
public EqualsBuilder Append(float lhs, float rhs)
{
  if (isEqual == false)
  {
    return this;
  }
  // java impl: 
  // return append(
  //   Float.floatToIntBits(lhs), 
  //   Float.floatToIntBits(rhs));
  return Append(
    BitConverter.SingleToInt32Bits(lhs), 
    BitConverter.SingleToInt32Bits(rhs));
}

Unfortunately, my above implementation of EqualsBuilder.Append(float lhs, float rhs) did not compile. Apparently, the BitConverter class in the .NET Framework 3.5 does not have a SingleToInt32Bits() method. Oh my!

Nevertheless, it’s quite easy to roll your own implementation of SingleToInt32Bits(), as indicated by these two useful pages:

Without further ado, here is one possible implementation of SingleToInt32Bits():

public static class MyBitConverter
{
  public static int SingleToInt32Bits(float value)
  {
    return BitConverter.ToInt32(BitConverter.GetBytes(value), 0);
  }
}

Pretty simple, huh? But does it work? Usually I like to practice Test Driven Development, in which you write your automated test code before you write the code that it tests. In this case, however, I had no idea of the output that should be produced for a given input into SingleToInt32Bits(). As a business application developer, I just don’t have much need for BitConverter methods!

After a tiny bit of thought, I realized that Java’s Float.floatToIntBits() method should produce the same output as my SingleToInt32Bits() method, given the same input. Here is a lame Java program that calls Float.floatToIntBits() with a few sample inputs:

class JavaBitConverterExperiments 
{
  public static void main(String[] args) 
  {
    float floatValue = 1.0F;
    System.out.printf("%1.1f %d\n", floatValue, 
      Float.floatToIntBits(floatValue));
    
    floatValue = 24.154F;
    System.out.printf("%2.3f %d\n", floatValue, 
      Float.floatToIntBits(floatValue));
    
    floatValue = Float.POSITIVE_INFINITY;
    System.out.printf("%f %x\n", floatValue, 
      Float.floatToIntBits(floatValue));
    
    floatValue = Float.NEGATIVE_INFINITY;
    System.out.printf("%f %x\n", floatValue, 
      Float.floatToIntBits(floatValue));
    
    floatValue = Float.NaN;
    System.out.printf("%f %x\n", floatValue, 
      Float.floatToIntBits(floatValue));   
  }
}

That Java program produced the following output:

1.0 1065353216
24.154 1103182692
Infinity 7f800000
-Infinity ff800000
NaN 7fc00000

I also made a similar (also lame) C# program that calls SingleToInt32Bits() with the same inputs:

class Program
{
  static void Main(string[] args)
  {
    float floatValue = 1.0F;
    Console.WriteLine(
      "{0:f1} {1}",
      floatValue,
      MyBitConverter.SingleToInt32Bits(floatValue));

    floatValue = 24.154F;
    Console.WriteLine(
      "{0:f3} {1}",
      floatValue,
      MyBitConverter.SingleToInt32Bits(floatValue));

    floatValue = float.PositiveInfinity;
    Console.WriteLine(
      "{0:f} {1:x}",
      floatValue,
      MyBitConverter.SingleToInt32Bits(floatValue));

    floatValue = float.NegativeInfinity;
    Console.WriteLine(
      "{0:f} {1:x}",
      floatValue,
      MyBitConverter.SingleToInt32Bits(floatValue));

    floatValue = float.NaN;
    Console.WriteLine(
      "{0:f} {1:x}",
      floatValue,
      MyBitConverter.SingleToInt32Bits(floatValue));
  }
}

That C# program produced the following output:

1.0 1065353216
24.154 1103182692
Infinity 7f800000
-Infinity ff800000
NaN ffc00000

As you can see, the Java program and the C# program produced the same output for the same input, except in the case of the input NaN. Was my C# code wrong?

No. As it turns out, there is actually a range of acceptable values for NaN and both 7fc00000 and ffc00000 can be used to represent NaN. Still, it begs the question: why doesn’t .NET use the same value for NaN as Java? You can go ask Bill but I guess it doesn’t really matter.

Anyway, if you came here looking for an implementation of SingleToInt32Bits(), I hope you found it. I do apologize for the excessive length of this article relative to the amount of code it took to implement the method. I just found some of the related side issues kind of interesting.

Be Sociable, Share!

    1 comment to An Implementation of BitConverter.SingleToInt32Bits

    • Joe,
      “I had to tweak the code a bit to make all the tests pass and to make both classes work a little more like their Java counterparts.”
      Could you share all your changes which you think worth to commit them in source code for community sharing? :)

      Thank you