0

How can I find information about float datatype in C? I mean the bit struct for this type (decimal, signal indicator, etc...)? Let me explain what I'm trying to do:

I am implementing an network protocol and I need to send 6 octects with Latitude and Longitude (according to protocol documentation). First 3 octects must have LAT information and last 3 must have LON information. I can't use bitwise operators in float datatype, so for debug, I'm copying memory of float variable to a new uint32_t variable (both 4-bytes wide) and then, trying to shift bit's to get the correct value, but it's not working.

This is the code that I'm using to test/debug conversion:

    int32_t b = 0;    
    memcpy(&b,&a,4);
    int32_t c = (b >> 23);        
    printf("Valor de C: 0x%X, Decimal: %d\n",c,c);
// Should print only '23', but it's printing 
// Valor de C: 0x41B, Decimal: 1051

After 'knowing' the correct bit-position of float, I'll copy those bit's to my protocol data, which is an array of unsigned char[6] (this I can't change the type, only values).

Any tip's about how to accomplish this? Information abour protocol

Jonis Maurin Ceará
  • 449
  • 1
  • 4
  • 11
  • 1
    Hello. Based on the protocol documentation you pasted, the data are not stored as float but fixed point number. You can read about the fixed point numbers here: https://en.wikipedia.org/wiki/Q_(number_format)#Conversion. – Jean-Marc Volle Jun 01 '20 at 13:33
  • 2
    You do not need to use the internal representation of the `float` type for this. You just need the value. The protocol you are using apparently wants the angle (latitude or longitude) encoded as the binary for an integer number of units, where the unit is 180/2\*\*23 degrees. So, if you have the angle as degrees in a `float`, convert it to a number of units by multiplying by 2\*\*23/180, and represent the result as a binary integer. – Eric Postpischil Jun 01 '20 at 13:37
  • https://stackoverflow.com/questions/385132 – Robert Harvey Jun 01 '20 at 13:38

3 Answers3

2

Here is a sample code showing how to encode the float latitude. (same thing for longitude). See: https://en.wikipedia.org/wiki/Q_(number_format)#Float_to_Q for an introduction to fixed point encoding with 2 complements sign management.

It uses fixed point encoding with weight provided by the specification.

#include <stdio.h>
#include <stdlib.h>
int main()
{

    /* weight of one bit */
    const float weight = 180./(1 << 23);
    printf ("w=%f\n",weight);

    /* a few sample conversions */
    /* 2.53 degres */
    float lat = 2.53; 
    printf ("lat=%f\n",lat);

    int fp_lat = (int) (0.5f + lat / weight);
    printf ("fplat=0x%x\n",fp_lat);

    lat = 180.f; /* +180 degres */
    printf ("lat=%f\n",lat);

    fp_lat = (int) (0.5f+ lat / weight);
    printf ("fplat=0x%6x\n",fp_lat); /*exactly 23 bits */

    /* negative numbers)*/
    lat = -180.f; /* -180 degres */

    printf ("lat=%f\n",lat);

    fp_lat = (int) (0.5f + abs(lat) / weight);
    if (lat <0)
    {
        /*2 complement representation */
        fp_lat = (~fp_lat + 1) & 0xffffff;
    }
    printf ("fplat=0x%6x\n",fp_lat); /* same value as 180 */


    /*sample packing for latitude */
    unsigned char msg[6];
    msg[0] = (unsigned char)((fp_lat >> 16) & 0xff); /* most significant byte of 24 bits*/
    msg[1] = (unsigned char)((fp_lat >> 8 ) & 0xff);
    msg[2] = (unsigned char)((fp_lat      ) & 0xff);

    /* to be continued */
    return 0;

}
Jean-Marc Volle
  • 3,113
  • 1
  • 16
  • 20
1

The interpretation of data is something separate from the data. The unit of the data is something separate from the data itself. So I can say 123 milliseconds or 0.123 seconds or 234 half-milliseconds or 1.23 * 10^-2 seconds and all these forms represent the same "value".

The data you posted I guess is composed of two numbers encoded in twos-complement numbers represented in big endian with most significant bit first.

unsigned char data[6]; // assuming indexes reference octet numbers
// big endian - first byte is the most significant
// I assume the hardware uses twos complement internally 
// the method as described in https://stackoverflow.com/questions/35876000/converting-24-bit-integer-2s-complement-to-32-bit-integer-in-c
int32_t latitude_value = (int32_t)( data[0] << 24 | data[1] << 16 | data[2] << 8 ) / 256;
// latitude_value represents latitude in units of 180/2^23 degrees

Now you can "transform" the latitute from units of 180/2^23 degrees to units of plain degrees if you want to represent it that way:

double latitue_in_degrees = (double)latitude * 180.0 / exp2(23);

Note that there are problems with floating point types.

What is the struct (binary format) of float datatype in C?
How can I find information about float datatype in C?
I mean the bit struct for this type (decimal, signal indicator, etc...)?

The exact format of float type depends on your compiler - it can be anything. Well, an overwhelming majority of systems/compilers today use binary32 format from IEC 754 standard for float datatype. Refer to the standard and endless net resources for the exact format of the datatype. For example this converter is just fun to use.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
-1

Usually for such purposes bit fields are used. You can try something like this:

#pragma pack(1)
typedef struct {
    union latitude{
        uint32_t value : 24;
        struct octets{
            uint8_t octetOne : 8;
            uint8_t octetTwo : 8;
            uint8_t octetThree : 8;
        }
    }
    union longitude{
        uint32_t value : 24;
        struct octets{
            uint8_t octetOne : 8;
            uint8_t octetTwo : 8;
            uint8_t octetThree : 8;
        }
    }
} frame;

Then store incomming data in this struct and access desired values by: frame.longitude.value etc.

jbulatek
  • 154
  • 10
  • If padding is not enforced in the structure declaration, the mapping may not work. – Jean-Marc Volle Jun 01 '20 at 14:09
  • 1
    `#pragma pack(1)` is microsoft specific pragma. `Usually for such purposes bit fields are used` in code that is aiming for one specific compiler and architecture that supports packing fields in a storage unit in a specific, certain way. Sadly, bit fields are not portable between machines and compilers, bit masks are preferred. – KamilCuk Jun 01 '20 at 14:22
  • 1
    You proposal assumes that on the machine running the code, the msb of `value` will have the lowest address in memory. This is not something you can always expect (endianess issues) – Jean-Marc Volle Jun 01 '20 at 14:26