8

I'd like to convert a given float into its binary representation. I tried to write the float value into a MemoryStream, read this MemoryStream byte by byte and convert the bytes into their binary representation. But every attempt failed.

  • "Can't read closed stream" (but I only closed the writer)
  • For test purposes I simply wrote an integer (I think four bytes in size) and the length of the MemoryStream was 0, when I didn't flush the StreamWriter, and 1, when I did.

I'm sure there is a better way to convert floats to binary, but I also wanted to learn a little bit about the MemoryStream class.

Cubi73
  • 1,891
  • 3
  • 31
  • 52

6 Answers6

16

You can use BitConverter.GetBytes(float) or use a BinaryWriter wrapping a MemoryStream and use BinaryWriter.Write(float). It's not clear exactly what you did with a MemoryStream before, but you don't want to use StreamWriter - that's for text.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • OK. I always forget, which class to use for a specific purpose :) Thank you for the quick answer :) – Cubi73 Jan 20 '14 at 21:31
  • 1
    @Cubinator73: That's what the documentation's for. For example, from `StreamWriter`: "Implements a TextWriter for writing characters to a stream in a particular encoding" - that's not what you're after. – Jon Skeet Jan 20 '14 at 21:33
  • Is there a more efficient approach that for instance writes the data to an `uint` (for `float`) and `ulong` (for `double`)? Using a `byte[]` array probably requires the construction of an object on the heap and doesn't provide easy bitwise manipulation. – Willem Van Onsem Jan 27 '15 at 13:39
  • 1
    @CommuSoft: For `double` there's [`BitConverter.DoubleToInt64Bits`](https://msdn.microsoft.com/en-us/library/system.bitconverter.doubletoint64bits) I don't know of anything similar for `float`. – Jon Skeet Jan 27 '15 at 13:43
  • 2
    Found something on [this page](http://stackoverflow.com/questions/24420086/specify-a-specific-double-precision-literal-in-c-sharp). Converting using unsafe pointers: `ulong db=*(ulong*)&d;` or `uint fb=*(uint*)&f;`. This probably is the most efficient way. – Willem Van Onsem Jan 27 '15 at 13:53
  • @CommuSoft: Well that will basically be what `BitConverter` does - but without requiring you to have unsafe code :) – Jon Skeet Jan 27 '15 at 14:23
6

Using BitConverter, not MemoryStream:

        // -7 produces "1 10000001 11000000000000000000000"
        static string FloatToBinary(float f)
        {
            StringBuilder sb = new StringBuilder();
            Byte[] ba = BitConverter.GetBytes(f);
            foreach (Byte b in ba)
                for (int i = 0; i < 8; i++)
                {
                    sb.Insert(0,((b>>i) & 1) == 1 ? "1" : "0");
                }
            string s = sb.ToString();
            string r = s.Substring(0, 1) + " " + s.Substring(1, 8) + " " + s.Substring(9); //sign exponent mantissa
            return r;
        }
xyq.384.b
  • 2,086
  • 1
  • 13
  • 4
2

Dotnetfiddle

BitConverter.GetBytes(3.141f)
            .Reverse()
            .Select(x => Convert.ToString(x, 2))
            .Select(x => x.PadLeft(8, '0'))
            .Aggregate("0b", (a, b) => a + "_" + b);

// res = "0b_01000000_01001001_00000110_00100101"

Couldn't resist to use a "small" LINQ Query. Works with double too.

juwens
  • 3,729
  • 4
  • 31
  • 39
1

You might have run into a pitfall when using StreamWriter, as the following code shows:

        // Write the float
        var f = 1.23456f;
        var ms = new MemoryStream();
        var writer = new StreamWriter(ms);
        writer.Write(f);
        writer.Flush();

        // Read 4 bytes to get the raw bytes (Ouch!)
        ms.Seek(0, SeekOrigin.Begin);
        var buffer = new char[4];
        var reader = new StreamReader(ms);
        reader.Read(buffer, 0, 4);
        for (int i = 0; i < 4; i++)
        {
            Console.Write("{0:X2}", (int)buffer[i]);
        }
        Console.WriteLine();

        // This is what you actually read: human readable text
        for (int i = 0; i < buffer.Length; i++)
        {
            Console.Write(buffer[i]);
        }
        Console.WriteLine();

        // This is what the float really looks like in memory.
        var bytes = BitConverter.GetBytes(f);
        for (int i = 0; i < bytes.Length; i++)
        {
            Console.Write("{0:X2}", (int)bytes[i]);
        }

        Console.ReadLine();

If you expect only 4 bytes to be in the stream and read those 4 bytes, everything looks fine at first sight. But actually the length is 7 and you have read only the first 4 bytes of the text representation of the float.

Comparing that to the output of the BitConverter reveals that using StreamWriter is not the correct thing here.

Thomas Weller
  • 55,411
  • 20
  • 125
  • 222
0

To answer your first question: In .Net, when you close/dispose a reader/writer, the underlying stream is also closed/disposed.

0

in 2017 .net added these:

For Float / Single ...

int rawBits     = BitConverter.SingleToInt32Bits(myFloat);
float backAgain = BitConverter.Int32BitsToSingle(rawBits);

For Double ...

int rawBits      = BitConverter.SingleToInt32Bits(myDouble);
double backAgain = BitConverter.Int32BitsToSingle(rawBits);
SunsetQuest
  • 8,041
  • 2
  • 47
  • 42