|
|
View previous topic :: View next topic |
Author |
Message |
marc10k
Joined: 15 Jan 2007 Posts: 11 Location: Germany
|
Float to int32, exact bit copy |
Posted: Wed Jul 25, 2007 3:15 am |
|
|
Hello
A int32 variable (return_value) is used to store 8, 16, 24 or 32 bits of data. These data will be send via RS232 later. If only 8 bity are stored only 1 byte will be transmitted, if 16 bits are stored 2 byte will be transmitted and so on. Now I have a float number (gmotor_vlt) that has to be copied into the int32 for transmission. I need an exact bit copy of the float.
Thanks for the help.
Marcus |
|
|
Ttelmah Guest
|
|
Posted: Wed Jul 25, 2007 4:43 am |
|
|
If you just want to send the four bytes comprising the float, or int32, then use a union:
Code: |
union access_bytes {
float fp;
int32 lword;
int16 word[2];
int8 b[4];
} data;
|
You can access 'data.fp', and use this as a normal float. You can get the bytes comprising it, through data.b[0] to data.b[3]. Similarly, data.lword, accesses the 32bit value, and can be read/written at will, while data.word[0] and data.word[1], access the two 16bit values.
However, if you want to write a float value 'into' an integer, then data will be lost.
A float, only contains 23.5 bits of information in the mantissa. If it is scaled without decimals, it allows only 1/362 of the possible range of a 32bit integer. While the integer (for example), can represent 400000001, exactly, a float can only represent, 400000000, and then 400000003 as the next possible value...
Best Wishes |
|
|
marc10k
Joined: 15 Jan 2007 Posts: 11 Location: Germany
|
|
Posted: Wed Jul 25, 2007 5:47 am |
|
|
The union is a good idea. The problem is I have to change a lot of code in my project in order to get it to work. Therefore it would be easier for me to get the float into the int32. I just want to copy the the "bit information" from the float into the int32. I am not interested in the value and don't want to convert the value. This is done later on the receiver side of the data.
Changing to union might be done later when the software works and I have some spare time.
example:
The float has the following byte pattern: 0x82470A3D
The result I would like to see in the int32: 0x82470A3D
The int32 just stores data "bit information" and not the data as a number. This makes it easier for me in the later program.
I have a question about the union. What is the word "acces_bytes" good for? When I want to access data i use the data.lword or data.b[2] for example. Can it be omitted? |
|
|
Ttelmah Guest
|
|
Posted: Wed Jul 25, 2007 9:21 am |
|
|
Access_bytes, is the 'name' of the union, so you can use it elsewhere, without having to redeclare it.
The easiest way to get at the bytes without redeclaring anything, is to use a pointer.
If you have a float 'fred', containing the value you want to send, then:
b=*((int8*)&fred);
will access the first byte of fred. While.
b=*(((int8*)&fred)+n);
will access the 'nth' byte of fred.
You generate a pointer to 'fred', and change this into a pointer to an 'int8', with the cast '(int8*)'. Since this is now a pointer to a single byte, you can increment it to access the other bytes.
There are dozens of 'tricks' you can also use:
For instance:
Code: |
void sendbytes(union access_bytes val) {
int8 ctr;
for (ctr=0;ctr<4;ctr++) printf("%2x",val.b[ctr]);
}
|
Will accept being called with a _float_, and because it is declared to access the union as already declared (obviously the declaration would need to be present, but would not need the 'data' part), would printout the 8 hex characters. The same trick can be used in dozens of other ways (sending the addresss for example, and declaring the receiving program to accept the address of a byte), so for instance:
Code: |
void send(int8 * bptr) {
int8 ctr;
for (ctr=0;ctr<4;ctr++) printf("%2x",bptr[ctr]);
}
|
Here, called with:
send(&a_float_val);
the routine will printout the hex values.
All of these work, because C is not a tightly 'typed' language, and will accept the _you_ know what type the value is. Here also, the implicit ability to switch between a pointer, and an array is used, so the address of a float is passed, treated as the address of an integer, and then handled as an array, all without actually having to 'do' anything, and without actually generating any code overhead either!...
Obviously, the printf, generates the hex values, but you could send the bytes as pure binary, the same way.
In fact the internal 'make8' routine, functions the same way, and should work with a float as well.
This is both one of the great 'powers' of C (since it allows easy access to the bytes), and one of the great 'dangers' (since if you get the declarations wrong, you can end up accessing the wrong type...).
Best Wishes |
|
|
marc10k
Joined: 15 Jan 2007 Posts: 11 Location: Germany
|
|
Posted: Fri Jul 27, 2007 2:04 am |
|
|
Thanks Ttelmah
Now it works the way I want it.
Here my function for copying the bits from a float into an int32. Probably some one else might need it. It might not be the best or the most elegant way but it works fine for my problem.
Code: | int32 float_to_int32(float value)
{
int32 int32_val=0;
int loop;
for (loop=0; loop < 3; loop++)
{
int32_val|=*(((int8*)&value)+loop);
int32_val <<= 8;
}
int32_val|=*(((int8*)&value)+3);
return int32_val;
} |
The int32_val has to be set to zero at the beginning otherwise the returned data will be wrong due to the |=.
Marcus |
|
|
Ttelmah Guest
|
|
Posted: Fri Jul 27, 2007 2:40 am |
|
|
You can do this two other ways.
First, is implicit in my comments about lack of type testing in C. Simply do this:
Code: |
int32 float_to_int32(int32 value)
{
return value;
}
|
Call this with a _float_ and it'll return the int32 containing the bytes!....
Second, is to use the memcpy function.
Code: |
int32 float_to_int32(float value)
{
int32 int32_val=0;
memcpy(&int32_val,&value,4);
return int32_val;
}
|
Best Wishes |
|
|
marc10k
Joined: 15 Jan 2007 Posts: 11 Location: Germany
|
|
Posted: Fri Jul 27, 2007 2:54 am |
|
|
Tried both functions and they work fine. Just the LSB are swapped with the MSB compared to my code.
Thanks again for some inspiration and better understanding of C.
Marcus |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|