Convert Bytes To Floating Point Numbers

Rate this post

Summary: The struct module in Python, taken from the C programming language, lets you convert bytes to and from floating point numbers.


Problem: How to convert bytes to floating point numbers?

A quick look at the solution:

A Brief Introduction to Struct

The struct module has three main methods for data conversion:

  • unpack(),
  • pack()
  • calcsize().

➦ You can use the unpack() method to convert bytes to floating point numbers. The method accepts data format and the byte to be converted.

struct.unpack("f", <byte>)

➦ On the other hand, the pack() method helps in converting data types to bytes.

struct.pack("f", <floating point number>)

Where f stands for floats. As you will see in other parts of this tutorial, the struct module handles different data types such as characters, integers and floats. But before that, you should understand bytes, floating point numbers, and the concept of structs.

Definition Of Bytes And Floating Point Numbers

This section focuses on the roots of bytes and data formats.

Unlike humans that represent numbers in base 10 (0 to 9 digits), computers understand the language of 1s and 0s. A pair of 1 and 0 is a binary digit, shortened as a bit. So, the computer converts data into a series of 1s and 0s (bits) before storing them in the memory.

Likewise, non-numerical data get stored as bytes. For instance, a character occupies 1 byte of memory. An array of characters forms a string.

FormatType in C programming languagesize in bytes
cchar1
bsigned char1
Bunsigned char1
?_Bool1
hshort2
Hunsigned short2
iint4
Iunsigned int4
llong4
Lunsigned long4
qlong long8
Qunsigned long long8
schar[]
ffloat4

Now that you understand how a computer interprets various data types, it would be best to learn how the struct module uses them to convert bytes to floating point numbers. Since struct has been taken from the C programming language, hence, a deeper understanding of how it works in C is crucial.

Struct Padding vs Packing

In the C programming language, a struct is a user-defined data type. Unlike other variables, a struct combines different data types in a structure. Here is an example.

struct Fruit {
    char firstLetter;
    int total;
};

We are creating a blueprint of a Fruit with a firstLetter character, and total integer. We can create a banana from the Fruit model, assigning it b as firstLetter and 23 as total.

struct Fruit fruit1 = { 'b', 23 };

Printing the size of each attribute,

printf("firstLetter is %d bytes and total is %d bytes \n", sizeof(fruit1.firstLetter),sizeof(fruit1.number));

we get the result as

firstLetter is 1 bytes and total is 4 bytes

The size of fruit1 should be (1 + 4 =) 5 bytes, right? Let’s check.

Size of fruit1 is 8 bytes

It turns out our computer uses more memory to store smaller data quantities. That happens due to a concept called padding.

CPU reads 4 bytes of data per cycle. For the first cycle, it adds three bytes of space to the available (1) byte and returns the result. Next, it finds 4 bytes and returns them. In total, it records (4 + 4 =) 8 bytes.

Padding wastes memory while reducing CPU cycles. Struct packing comes in to store more bytes in less memory.

#include <stdio.h>
#pragma pack(1)

struct Fruit {
    char firstLetter;
    int number;
};

int main () {

    struct Fruit fruit1 = { 'b', 23 };

    // printf("firstLetter is %d bytes and total is %d bytes \n", sizeof(fruit1.firstLetter),sizeof(fruit1.number));
    printf("Size of fruit1 is %d bytes \n", sizeof(fruit1));

    return 0;
}

We include #pragma pack(1) header with pack function of value 1 to reduce the memory wastage when compiling and assembling data. This time around, the struct size is what we expect: 1 byte + 4 bytes = 5 bytes.

Size of fruit1 is 5 bytes 

The key takeaway is that struct is a C programming language data structure for storing user-defined data types. Unlike other data types, it combines a continuous stream of different data types. The various data types consume more memory due to padding, something we can control using struct packing.

We can apply the concept of struct to convert data types to bytes in Python, as illustrated below.

How To Use The Struct Module In Python

Unlike C, which speaks to the memory through data types and compiling, Python is a high-level, dynamically-typed programming language. Most operations occur through modules (classes) that get translated and compiled to produce bytes. One such module is the struct module.
The struct module has three methods: pack(), unpack(), and calcsize(). The pack method accepts two parameters: format and data to be converted to bytes. Like the struct blueprint in C, the format part of the pack function in Python accepts various data types. For example,

struct.pack('iif', 2, 4, 7.68)

This means converting integer 2, integer 4 and float 7.68 to a stream of bytes. i stands for an integer while f represents floats.

You can represent repeating integers by a numeral. For example, iii can map to 3i. Also, you can separate the data types with a space. For example, 3i f is another representation for 3if.

We can check the format size by importing the module,

import struct 

and using its calcsize() method.

struct.calcsize('3if')

In the same way, we can convert a floating point number into bytes. Assume we want to convert 3.76 to bytes. We can do that using the following code.

byteData = struct.pack('f', 3.76)

print(byteData)

Output:

b'\xd7\xa3p@'

Here, b stands for bytes. The other parts may differ as per computer depending on the memory address system and endianness. Let’s now find floating point numbers from bytes.

Convert Bytes To Floating Point Numbers

The unpack function accepts format, and the byte stream then converts it to a floating point number. For example, we can decode b'\xd7\xa3p@' as follows.

byteData = struct.unpack('f', b'\xd7\xa3p@')

print(byteData)

The result is a tuple containing a floating point number with a massive number of decimal points.

(3.759999990463257,)

We can extract the result by surrounding the input with square brackets.

[byteData] = struct.unpack('f', b'\xd7\xa3p@')

The result of printing the output is 3.759999990463257.

The extended decimal output from a reduced input size shows the essence of scientific notation in computing. It also proves the reason for the preference of floating point numbers over integers.

Apart from efficiency, handling floating point numbers comes with speed since much work has gone into building floating point numbers over the years.

Conclusion

The struct module with its unpack() method helps convert bytes to floating point numbers. It would help to understand other methods such as pack() and calcsize because, from them, you can generate bytes from various data types.

Another way to ease handling the conversion is understanding the ins and outs of the struct module, as explained in this tutorial.