Converting 'float' to 'byte[4]' and back to 'float' in .NET Micro Framework
Asked Answered
P

3

6

What's the best way to convert a float to a byte[4] and then back to a 'float'?

I am doing this in C# .NET Micro Framework, so there is no BitConverter available for my use.

Plebs answered 20/1, 2011 at 2:25 Comment(9)
be careful of endianness (the link from @Mitch shows a BitConverter class that uses little endian)Spessartite
The platform that encodes the float does not have any sort of BitConverter class. Nothing that uses a BitConverter class of any type will work.Plebs
Nevermind, looks like it's open source, I can just extract the bits out that I need.Plebs
These floats are now diamonds.Formosa
So far, nothing I have tried has really worked. Can anyone suggest a answer that uses pure bitwise operations?Plebs
I'm assuming you tried the class from the previously mentioned link (which supposedly was written for C# .NETMF). Please explain how it didn't work: Which functions did you try? and what did you expect for output?Spessartite
I can't use it because these bytes are getting exchanged between two targets. One of which is not running NETMF. They are being encoded on one and decoded on the other. The other target is an Arduino.Plebs
You might have an endianness mismatch; one is encoding in little endian while the other is decoding in big endian. You'll have to modify the class to allow specifying endianness, and pick the same endianness on both platforms.Spessartite
@Formosa Of all the nonsense. I'm on a horse.Ailin
S
3

I've modified the BitConverter class from a Netduino implementation to allow endianness specification (it's not the "best way", but it works). If the byte array is sent over the network, I would use BigEndian. Just a reminder that unsafe is not officially supported in NETMF.

using System;
using System.Diagnostics;

namespace netduino
{
    public static class BitConverter
    {
        public static byte[] GetBytes(uint value)
        {
            return new byte[4] { 
                    (byte)(value & 0xFF), 
                    (byte)((value >> 8) & 0xFF), 
                    (byte)((value >> 16) & 0xFF), 
                    (byte)((value >> 24) & 0xFF) };
        }

        public static unsafe byte[] GetBytes(float value)
        {
            uint val = *((uint*)&value);
            return GetBytes(val);
        }

        public static unsafe byte[] GetBytes(float value, ByteOrder order)
        {
            byte[] bytes = GetBytes(value);
            if (order != ByteOrder.LittleEndian)
            {
                System.Array.Reverse(bytes);
            }
            return bytes;
        }

        public static uint ToUInt32(byte[] value, int index)
        {
            return (uint)(
                value[0 + index] << 0 |
                value[1 + index] << 8 |
                value[2 + index] << 16 |
                value[3 + index] << 24);
        }

        public static unsafe float ToSingle(byte[] value, int index)
        {
            uint i = ToUInt32(value, index);
            return *(((float*)&i));
        }

        public static unsafe float ToSingle(byte[] value, int index, ByteOrder order)
        {
            if (order != ByteOrder.LittleEndian)
            {
                System.Array.Reverse(value, index, value.Length);
            }
            return ToSingle(value, index);
        }

        public enum ByteOrder
        {
            LittleEndian,
            BigEndian
        }

        static public bool IsLittleEndian
        {
            get
            {
                unsafe
                {
                    int i = 1;
                    char* p = (char*)&i;

                    return (p[0] == 1);
                }
            }
        }
    }
}

namespace BitConverterTest
{
    class Program
    {
        static void Main(string[] args)
        {
            byte[] msbFirst = new byte[] { 0x42, 0xF6, 0xE9, 0xE0 };
            byte[] lsbFirst = new byte[] { 0xE0, 0xE9, 0xF6, 0x42 };
            const float f = 123.456789F;

            byte[] b = netduino.BitConverter.GetBytes(f, netduino.BitConverter.ByteOrder.BigEndian);
            for (int i = 0; i < b.Length; i++)
            {
                Debug.Assert(msbFirst[i] == b[i], "BitConverter.GetBytes(float, BigEndian) i=" + i);
            }

            Debug.Assert(f == netduino.BitConverter.ToSingle(msbFirst, 0, netduino.BitConverter.ByteOrder.BigEndian));

            Console.WriteLine("All tests passed");
            Console.ReadKey();
        }
    }
}
Spessartite answered 20/1, 2011 at 18:59 Comment(0)
C
10

The conversion from uint to float (and reverse) can be done with "safe" code as well (though I don't know if this is possible on the NETMF or not).

[StructLayout(LayoutKind.Explicit)]
struct UIntFloat
{       
    [FieldOffset(0)]
    public float FloatValue;

    [FieldOffset(0)]
    public uint IntValue;        
}

public static float ToSingle(byte[] value, int index)        
{           
    uint i = ToUInt32(value, index);            
    return ToSingle(i);
}

public static float ToSingle(uint value)
{
    UIntFloat uf = new UIntFloat();
    uf.IntValue = value;
    return uf.FloatValue;
}
Congreve answered 12/5, 2011 at 16:36 Comment(1)
Does it make any difference if the other variable is a uint or int?Panda
S
3

I've modified the BitConverter class from a Netduino implementation to allow endianness specification (it's not the "best way", but it works). If the byte array is sent over the network, I would use BigEndian. Just a reminder that unsafe is not officially supported in NETMF.

using System;
using System.Diagnostics;

namespace netduino
{
    public static class BitConverter
    {
        public static byte[] GetBytes(uint value)
        {
            return new byte[4] { 
                    (byte)(value & 0xFF), 
                    (byte)((value >> 8) & 0xFF), 
                    (byte)((value >> 16) & 0xFF), 
                    (byte)((value >> 24) & 0xFF) };
        }

        public static unsafe byte[] GetBytes(float value)
        {
            uint val = *((uint*)&value);
            return GetBytes(val);
        }

        public static unsafe byte[] GetBytes(float value, ByteOrder order)
        {
            byte[] bytes = GetBytes(value);
            if (order != ByteOrder.LittleEndian)
            {
                System.Array.Reverse(bytes);
            }
            return bytes;
        }

        public static uint ToUInt32(byte[] value, int index)
        {
            return (uint)(
                value[0 + index] << 0 |
                value[1 + index] << 8 |
                value[2 + index] << 16 |
                value[3 + index] << 24);
        }

        public static unsafe float ToSingle(byte[] value, int index)
        {
            uint i = ToUInt32(value, index);
            return *(((float*)&i));
        }

        public static unsafe float ToSingle(byte[] value, int index, ByteOrder order)
        {
            if (order != ByteOrder.LittleEndian)
            {
                System.Array.Reverse(value, index, value.Length);
            }
            return ToSingle(value, index);
        }

        public enum ByteOrder
        {
            LittleEndian,
            BigEndian
        }

        static public bool IsLittleEndian
        {
            get
            {
                unsafe
                {
                    int i = 1;
                    char* p = (char*)&i;

                    return (p[0] == 1);
                }
            }
        }
    }
}

namespace BitConverterTest
{
    class Program
    {
        static void Main(string[] args)
        {
            byte[] msbFirst = new byte[] { 0x42, 0xF6, 0xE9, 0xE0 };
            byte[] lsbFirst = new byte[] { 0xE0, 0xE9, 0xF6, 0x42 };
            const float f = 123.456789F;

            byte[] b = netduino.BitConverter.GetBytes(f, netduino.BitConverter.ByteOrder.BigEndian);
            for (int i = 0; i < b.Length; i++)
            {
                Debug.Assert(msbFirst[i] == b[i], "BitConverter.GetBytes(float, BigEndian) i=" + i);
            }

            Debug.Assert(f == netduino.BitConverter.ToSingle(msbFirst, 0, netduino.BitConverter.ByteOrder.BigEndian));

            Console.WriteLine("All tests passed");
            Console.ReadKey();
        }
    }
}
Spessartite answered 20/1, 2011 at 18:59 Comment(0)
M
-1

This worked for me, may not be the most complete answer but simple

void floatToByte(GLubyte b[], float n)
{
unsigned int val = *((unsigned int*)&n);

b[0] = (GLubyte)(val  & 0xFF);
b[1] = (GLubyte)((val >> 8) & 0xFF);
b[2] = (GLubyte)((val >> 16) & 0xFF);
b[3] = (GLubyte)((val >> 24) & 0xFF);   
}



float byteToFloat(GLubyte b[])
{
unsigned int ret =  (unsigned int)(b[0] << 0 | b[1] << 8 | b[2] << 16 | b[3] << 24);
float r = *(((float*)&ret));
return r;
}
Manful answered 14/12, 2012 at 20:18 Comment(1)
this isn't even C#!Mckellar

© 2022 - 2024 — McMap. All rights reserved.