Search Unity

Converting float to byte

Discussion in 'Scripting' started by Lab013, Apr 10, 2011.

  1. Lab013

    Lab013

    Joined:
    Oct 22, 2008
    Posts:
    405
    Greeting, I am having some trouble with saving a binary, I need to convert a float to a byte while keeping the bit pattern in tact (so I don't want to convert it to an integer). Anyone know how I'd go about doing this?
     
  2. McRain

    McRain

    Joined:
    Mar 26, 2009
    Posts:
    138
  3. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    MGGDev likes this.
  4. Lab013

    Lab013

    Joined:
    Oct 22, 2008
    Posts:
    405
    Just what I needed, thank you!
     
  5. RajneeshG

    RajneeshG

    Joined:
    Jan 3, 2014
    Posts:
    15
  6. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,531
    4 years old...
     
  7. McRain

    McRain

    Joined:
    Mar 26, 2009
    Posts:
    138
    Thanks for the tip.
    Fixed.
     
  8. BillyMFT

    BillyMFT

    Joined:
    Mar 14, 2013
    Posts:
    178
    Think it's still broken.

    Thanks
     
  9. McRain

    McRain

    Joined:
    Mar 26, 2009
    Posts:
    138
    Yes, my blog is temporarily being repaired).

    use
    Code (csharp):
    1. BitConverter.GetBytes((float)inObject);
    and
    Code (csharp):
    1. BitConverter.ToSingle(inBytes, 0);
     
  10. churi24

    churi24

    Joined:
    Sep 17, 2013
    Posts:
    98
    Maybe this could be useful

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections.Generic;
    3. using System;
    4.  
    5. public class UnitySerializer : MonoBehaviour{
    6.  
    7.     private List<byte> byteStream = new List<byte>();
    8.     private byte[] byteArray;
    9.     private int index = 0;
    10.  
    11.     /// <summary>
    12.     /// Returns the stream as a Byte Array
    13.     /// </summary>
    14.     public byte[] ByteArray  
    15.     {
    16.         get
    17.         {
    18.             if ( byteArray == null || byteStream.Count != byteArray.Length)
    19.                 byteArray = byteStream.ToArray();
    20.          
    21.             return byteArray;
    22.         }
    23.     }
    24.  
    25.     /// <summary>
    26.     /// Create a new empty stream
    27.     /// </summary>
    28.     public UnitySerializer()
    29.     {
    30.      
    31.     }
    32.  
    33.     /// <summary>
    34.     /// Initialiaze a stream from a byte array.
    35.     /// Used for deserilaizing a byte array
    36.     /// </summary>
    37.     /// <param name="ByteArray"></param>
    38.     public UnitySerializer(byte[] ByteArray)
    39.     {
    40.         byteArray = ByteArray;
    41.         byteStream = new List<byte>(ByteArray);
    42.     }
    43.  
    44.  
    45.  
    46.     // --- double ---
    47.     public void Serialize(double d)
    48.     {
    49.         byteStream.AddRange( BitConverter.GetBytes(d));
    50.      
    51.     }
    52.  
    53.     public double DeserializeDouble()
    54.     {
    55.         double d = BitConverter.ToDouble(ByteArray, index); index += 8;
    56.         return d;
    57.     }
    58.     //
    59.  
    60.     // --- bool ---
    61.     public void Serialize(bool b)
    62.     {
    63.         byteStream.AddRange(BitConverter.GetBytes(b));
    64.     }
    65.  
    66.     public bool DeserializeBool()
    67.     {
    68.         bool b = BitConverter.ToBoolean(ByteArray, index); index += 1;
    69.         return b;
    70.     }
    71.     //
    72.  
    73.     // --- Vector2 ---
    74.     public void Serialize(Vector2 v)
    75.     {
    76.         byteStream.AddRange(GetBytes(v));
    77.     }
    78.  
    79.     public Vector2 DeserializeVector2()
    80.     {
    81.         Vector2 vector2 = new Vector2();
    82.         vector2.x = BitConverter.ToSingle(ByteArray, index); index += 4;
    83.         vector2.y = BitConverter.ToSingle(ByteArray, index); index += 4;
    84.         return vector2;
    85.     }
    86.     //
    87.  
    88.     // --- Vector3 ---
    89.     public void Serialize(Vector3 v)
    90.     {
    91.         byteStream.AddRange(GetBytes(v));
    92.     }
    93.  
    94.     public Vector3 DeserializeVector3()
    95.     {
    96.         Vector3 vector3 = new Vector3();
    97.         vector3.x = BitConverter.ToSingle(ByteArray, index); index += 4;
    98.         vector3.y = BitConverter.ToSingle(ByteArray, index); index += 4;
    99.         vector3.z = BitConverter.ToSingle(ByteArray, index); index += 4;
    100.         return vector3;
    101.     }
    102.     //
    103.  
    104.     // --- Type ---
    105.     public void Serialize(System.Type t)
    106.     {
    107.         // serialize type as string
    108.         string typeStr = t.ToString();
    109.         Serialize(typeStr);
    110.     }
    111.  
    112.     public Type DeserializeType()
    113.     {
    114.         // type stored as string
    115.         string typeStr = DeserializeString();
    116.         return Type.GetType(typeStr); ;
    117.     }
    118.     //
    119.  
    120.     // --- String ---
    121.     public void Serialize(string s)
    122.     {
    123.         // add the length as a header
    124.         byteStream.AddRange(BitConverter.GetBytes(s.Length));
    125.         foreach (char c in s)
    126.             byteStream.Add((byte)c);
    127.     }
    128.  
    129.     public string DeserializeString()
    130.     {
    131.         int length = BitConverter.ToInt32(ByteArray, index); index += 4;
    132.         string s = "";
    133.         for (int i = 0; i < length; i++)
    134.         {
    135.             s += (char)ByteArray[index];
    136.             index++;
    137.         }
    138.      
    139.         return s;
    140.     }
    141.     //
    142.  
    143.     // --- byte[] ---
    144.     public void Serialize(byte[] b)
    145.     {
    146.         // add the length as a header
    147.         byteStream.AddRange(BitConverter.GetBytes(b.Length));
    148.         byteStream.AddRange(b);
    149.     }
    150.  
    151.     public byte[] DeserializeByteArray()
    152.     {
    153.         int length = BitConverter.ToInt32(ByteArray, index); index += 4;
    154.         byte[] bytes = new byte[length];
    155.         for (int i = 0; i < length; i++)
    156.         {
    157.             bytes[i] = ByteArray[index];
    158.             index++;
    159.         }
    160.      
    161.         return bytes;
    162.     }
    163.     //
    164.  
    165.     // --- Quaternion ---
    166.     public void Serialize(Quaternion q)
    167.     {
    168.         byteStream.AddRange(GetBytes(q));
    169.     }
    170.  
    171.     public Quaternion DeserializeQuaternion()
    172.     {
    173.         Quaternion quat = new Quaternion();
    174.         quat.x = BitConverter.ToSingle(ByteArray, index); index += 4;
    175.         quat.y = BitConverter.ToSingle(ByteArray, index); index += 4;
    176.         quat.z = BitConverter.ToSingle(ByteArray, index); index += 4;
    177.         quat.w = BitConverter.ToSingle(ByteArray, index); index += 4;
    178.         return quat;
    179.     }
    180.     //
    181.  
    182.     // --- float ---
    183.     public void Serialize(float f)
    184.     {
    185.         byteStream.AddRange(BitConverter.GetBytes(f));
    186.     }
    187.  
    188.     public float DeserializeFloat()
    189.     {
    190.         float f = BitConverter.ToSingle(ByteArray, index); index += 4;
    191.         return f;
    192.     }
    193.     //
    194.  
    195.     // --- int ---
    196.     public void Serialize(int i)
    197.     {
    198.         byteStream.AddRange(BitConverter.GetBytes(i));
    199.     }
    200.  
    201.     public int DeserializeInt()
    202.     {
    203.         int i = BitConverter.ToInt32(ByteArray, index); index += 4;
    204.         return i;
    205.     }
    206.     //
    207.  
    208.     // --- internal ----
    209.     Vector3 DeserializeVector3(byte[] bytes, ref int index)
    210.     {
    211.         Vector3 vector3 = new Vector3();
    212.         vector3.x = BitConverter.ToSingle(bytes, index); index += 4;
    213.         vector3.y = BitConverter.ToSingle(bytes, index); index += 4;
    214.         vector3.z = BitConverter.ToSingle(bytes, index); index += 4;
    215.      
    216.         return vector3;
    217.     }
    218.  
    219.     Quaternion DeserializeQuaternion(byte[] bytes, ref int index)
    220.     {
    221.         Quaternion quat = new Quaternion();
    222.         quat.x = BitConverter.ToSingle(bytes, index); index += 4;
    223.         quat.y = BitConverter.ToSingle(bytes, index); index += 4;
    224.         quat.z = BitConverter.ToSingle(bytes, index); index += 4;
    225.         quat.w = BitConverter.ToSingle(bytes, index); index += 4;
    226.         return quat;
    227.     }
    228.  
    229.     byte[] GetBytes(Vector2 v)
    230.     {
    231.         List<byte> bytes = new List<byte>(8);
    232.         bytes.AddRange(BitConverter.GetBytes(v.x));
    233.         bytes.AddRange(BitConverter.GetBytes(v.y));
    234.         return bytes.ToArray();
    235.     }
    236.  
    237.     byte[] GetBytes(Vector3 v)
    238.     {
    239.         List<byte> bytes = new List<byte>(12);
    240.         bytes.AddRange(BitConverter.GetBytes(v.x));
    241.         bytes.AddRange(BitConverter.GetBytes(v.y));
    242.         bytes.AddRange(BitConverter.GetBytes(v.z));
    243.         return bytes.ToArray();
    244.     }
    245.  
    246.     byte[] GetBytes(Quaternion q)
    247.     {
    248.         List<byte> bytes = new List<byte>(16);
    249.         bytes.AddRange(BitConverter.GetBytes(q.x));
    250.         bytes.AddRange(BitConverter.GetBytes(q.y));
    251.         bytes.AddRange(BitConverter.GetBytes(q.z));
    252.         bytes.AddRange(BitConverter.GetBytes(q.w));
    253.         return bytes.ToArray();
    254.     }
    255.  
    256. //    public static void Example()
    257. //    {
    258. //        //
    259. //        Debug.Log("--- UnitySerializer Example ---");
    260. //        Vector2 point      = UnityEngine.Random.insideUnitCircle;
    261. //        Vector3 position    = UnityEngine.Random.onUnitSphere;
    262. //        Quaternion quaternion  = UnityEngine.Random.rotation;
    263. //        float f         = UnityEngine.Random.value;
    264. //        int i          = UnityEngine.Random.Range(0, 10000);
    265. //        double d        = (double)UnityEngine.Random.Range(0, 10000);
    266. //        string s        = "Brundle Fly";
    267. //        bool b         = UnityEngine.Random.value < 0.5f ? true : false;
    268. //        System.Type type    = typeof(UnitySerializer);
    269. //      
    270. //        //
    271. //        Debug.Log("--- Before ---");
    272. //        Debug.Log(point + " " + position + " " + quaternion + " " + f + " " + d + " " + s + " " + b + " " + type);
    273. //      
    274. //        //
    275. //        Debug.Log("--- Serialize ---");
    276. //        UnitySerializer us = new UnitySerializer();
    277. //        us.Serialize(point);
    278. //        us.Serialize(position);
    279. //        us.Serialize(quaternion);
    280. //        us.Serialize(f);
    281. //        us.Serialize(i);
    282. //        us.Serialize(d);
    283. //        us.Serialize(s);
    284. //        us.Serialize(b);
    285. //        us.Serialize(type);
    286. //        byte[] byteArray = us.ByteArray;
    287. //      
    288. //        // the array must be deserialized in the same order as it was serialized
    289. //        Debug.Log("--- Deserialize ---");
    290. //        UnitySerializer uds   = new UnitySerializer(byteArray);
    291. //        Vector2 point2     = uds.DeserializeVector2();
    292. //        Vector3 position2    = uds.DeserializeVector3();
    293. //        Quaternion quaternion2 = uds.DeserializeQuaternion();
    294. //        float f2        = uds.DeserializeFloat();
    295. //        int i2         = uds.DeserializeInt();
    296. //        double d2        = uds.DeserializeDouble();
    297. //        string s2        = uds.DeserializeString();
    298. //        bool b2         = uds.DeserializeBool();
    299. //        System.Type type2    = uds.DeserializeType();
    300. //      
    301. //        //
    302. //        Debug.Log("--- After ---");
    303. //        Debug.Log(point2 + " " + position2 + " " + quaternion2 + " " + f2 + " " + d2 + " " + s2 + " " + b2 + " " + type2);
    304. //    }
    305. }  
     
  11. chadfranklin47

    chadfranklin47

    Joined:
    Aug 11, 2015
    Posts:
    226
    A bit late, but what do you mean not endian safe?
     
  12. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,609
    https://en.wikipedia.org/wiki/Endianness
     
  13. chadfranklin47

    chadfranklin47

    Joined:
    Aug 11, 2015
    Posts:
    226
  14. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,334
    It's a complex topic, and not really easy to ELI5. You have to understand at least the basics of storing data as bits.

    The consequences of not being endian safe is that data saved on one computer might not be possible to load on a different computer. So if you're making save games for a local thing, it's fine, but if you're making something like cloud saves, it's not a good idea.

    very simplified:
    "big endian" and "small endian" boils down to if the bits of your data is stored left-to-right or right-to-left. For a byte, that's the difference between:
    4 = 00000100 <- big endian, biggest bit stored first
    and
    4 = 00100000 <- small endian, biggest bit stored last

    So if you have a small-endian 4 that's read of as if it was big-endian, you'd get 64 instead.
     
  15. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Endian is byte-order, not bit-order. e.g., a 16-bit big-endian number stored as two bytes has the "largest" (most significant) byte first, followed by the least significant byte. Little-endian is the opposite. Nothing to do with bits; 00000100 is always 4.

    --Eric
     
  16. chadfranklin47

    chadfranklin47

    Joined:
    Aug 11, 2015
    Posts:
    226
    Thanks for the help, so if i have a float, but want to send it as a ushort over the network, then convert it back to a float on the other players machine, i will run into problems?
     
  17. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Maybe, if you didn't use network byte order and the other machine's CPU had a different endianness than yours (not likely these days, even most consoles are x86-64 instead of PPC now).

    --Eric
     
  18. DonLoquacious

    DonLoquacious

    Joined:
    Feb 24, 2013
    Posts:
    1,667
    It's only the matter of a single line of code to check the endianness of the current machine's CPU (BitConverter.isLittleEndian) and know that you have to flip it. Worth noting that endianness is just a factor of integral types (int16, int32, int64) and not (I believe) a factor in floating point values. If you convert the float to ushort first, then to bytes, then transfer that, then put it back together into a ushort, then convert to float again, then endianness may matter and you should check the architecture when loading to ensure it's deserialized in the proper order. If it's not an integral type, it shouldn't matter.
     
    Last edited: Jan 8, 2018
  19. chadfranklin47

    chadfranklin47

    Joined:
    Aug 11, 2015
    Posts:
    226
    So if i only convert to ushort, and not to byte, I should be fine?
     
  20. DonLoquacious

    DonLoquacious

    Joined:
    Feb 24, 2013
    Posts:
    1,667
    I can account for the byte conversion, not for the network protocol. I have no idea what transfer method you're using, so I don't know if it automatically accounts for differences in architecture for known integral types. I would assume it would, so if you transfer a ushort on one end, it should be read property (in the right order) as a ushort on the other side. Conversion to byte arrays mean that the transfer protocol can't account for what data needs to be read one way or another. You could be transferring an integral type or not, who knows? So you have to handle flipping the array yourself, as appropriate.

    That's my limited understanding of the situation- I've never made a network game, so don't take it as gospel. If someone else could confirm this or correct me, that would be great.
     
  21. chadfranklin47

    chadfranklin47

    Joined:
    Aug 11, 2015
    Posts:
    226
    I wouldn't be using byte arrays, just a single byte or ushort. Dang, all of this confusing stuff makes me feel like I've not even scraped the surface of programming languages.
     
  22. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    Anything longer than a byte could be misread if you send it to another computer.
    It's up to you to make sure it arrives (and works) as intended :)
     
  23. Lenvanthis012

    Lenvanthis012

    Joined:
    Aug 24, 2013
    Posts:
    21
    float f;
    BinaryWriter writer = new BinaryWriter(File.Open(fileName, FileMode.Create));
    writer.Write(f);
    writer.Close();

    byte[] bytes = File.ReadAllBytes(fileName);
    // bytes will have byte [] representation of your float f
     
  24. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,531
    Did you really just necro a post to show code that uses disk IO to convert a float to it's byte representation?

    A solution that's also not endian safe, just like the 8 year old original answer which doesn't use disk IO.

    If so... the only good reason I could see to necro a post is to exercise your burgeoning programming skills. In which case some notes to take about your solution. You should avoid writing to a storage medium unless you're attempting to actually store something long term, or work with data sets significantly larger than working memory. Since you're not storing anything, and a float is a mere 4 bytes of memory, there's no reason to get the storage IO involved. It's probably the tightest bottleneck in your entire system.

    What you've effectively done is read a float from RAM, into the CPU, did some work on it, sent that result down the IO backplane (may that be over the pci-e bus, or worst through the southbridge) and onto a storage device. Then read that same data back up through the IO backplane likely through either the CPU or southbridge and back into RAM.

    Rather than... RAM -> CPU -> RAM which is probably the fastest pipe in your entire system (outside of the CPU itself, or the internals of your graphics card).
     
    Last edited: Dec 5, 2019