C Casting Problem
-
I have seen the term Fixed_32 for a data item with MSB = 1 and LSB = 1/2**31 ; Max = 1.0 and Min = -1.0 with units of semicircles (used for Latitude and Longitude) I did think this was a float to the IEEE-754 Floating-Point Representation. However the 3rd party that is reading some data via a message structure cannot see the same value. I mistaken the term Fixed_32 as a standard float but it is a 32 bit int in the message. The scalling is:-
#define BEARING_SCALING 4.65661287307739E-10
typedef struct ReceiveMessage
{
unsigned int msgNumber; // Msg number
int msgPosLat; // Msg latitude
int msgPosLong; // Msg longitude
unsigned int msgQuality; // Msg quality
}positionData#define BEARING_SCALING 4.65661287307739E-10
However I get a crash when I try to load the value (the Latitude was declared as a double and I tried to cast to the int and vice versa. Code:
// Note 180 is used to scale up from semicircles to degrees
double lat = 55.55;
positionData.msgPosLat = (int)(lat/(BEARING_SCALING * 180));// and the other way for reading:-
lat = (double)( positionData.msgPosLat) * BEARING_SCALING * 180;
What is going wrong please, is it the oder of casting or do I need to use fix point stuff?
-
I have seen the term Fixed_32 for a data item with MSB = 1 and LSB = 1/2**31 ; Max = 1.0 and Min = -1.0 with units of semicircles (used for Latitude and Longitude) I did think this was a float to the IEEE-754 Floating-Point Representation. However the 3rd party that is reading some data via a message structure cannot see the same value. I mistaken the term Fixed_32 as a standard float but it is a 32 bit int in the message. The scalling is:-
#define BEARING_SCALING 4.65661287307739E-10
typedef struct ReceiveMessage
{
unsigned int msgNumber; // Msg number
int msgPosLat; // Msg latitude
int msgPosLong; // Msg longitude
unsigned int msgQuality; // Msg quality
}positionData#define BEARING_SCALING 4.65661287307739E-10
However I get a crash when I try to load the value (the Latitude was declared as a double and I tried to cast to the int and vice versa. Code:
// Note 180 is used to scale up from semicircles to degrees
double lat = 55.55;
positionData.msgPosLat = (int)(lat/(BEARING_SCALING * 180));// and the other way for reading:-
lat = (double)( positionData.msgPosLat) * BEARING_SCALING * 180;
What is going wrong please, is it the oder of casting or do I need to use fix point stuff?
I think it works like this: the latitude in degrees ranges from -90 to +90 (and not -180 to +180). the encoding used is 32-bit fixed integers with an implied scale factor, so the full range [-90,+90] gets mapped onto the full integer range. So you want +90 represented by the largest positive 32-bit integer (which equals 2^31 minus one, or 0x7FFFFFFF), hence:
int fixed32(double lat) {
lat=lat/90.;
lat=lat*0x7FFFFFFF;
return (int)lat;
}Notes: 1. this code will never return the minimum value (0x80000000). For -90 it results in 0x80000001 which is a consequence of [-90,+90] being symmetric around zero, whereas the integer range [0x80000000, 0x7FFFFFFF] isn't. 2. I tend to avoid magic constants, such as the 4.65661287307739E-10 you had. I prefer to write them in a way that reveals what they stand for. Your value stems from 1.0/0x7FFFFFFF 3. I doubt the code you have shown would crash at all.
lat/(BEARING_SCALING * 180)
will not exceed the acceptable range for integers (and your formula being wrong by a factor of 2 IMO only reassures this).(positionData.msgPosLat) * BEARING_SCALING * 180)
may incur an integer overflow (again due to the factor of 2), but normally those get swallowed. So I expect if anything bombs, it must be the code that follows after you used these formulas, mainly the latitude going all the way up to +180. :)Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles] Nil Volentibus Arduum
Please use <PRE> tags for code snippets, and update CP Vanity to V2.0 if you haven't already.
modified on Thursday, December 9, 2010 3:45 PM
-
I think it works like this: the latitude in degrees ranges from -90 to +90 (and not -180 to +180). the encoding used is 32-bit fixed integers with an implied scale factor, so the full range [-90,+90] gets mapped onto the full integer range. So you want +90 represented by the largest positive 32-bit integer (which equals 2^31 minus one, or 0x7FFFFFFF), hence:
int fixed32(double lat) {
lat=lat/90.;
lat=lat*0x7FFFFFFF;
return (int)lat;
}Notes: 1. this code will never return the minimum value (0x80000000). For -90 it results in 0x80000001 which is a consequence of [-90,+90] being symmetric around zero, whereas the integer range [0x80000000, 0x7FFFFFFF] isn't. 2. I tend to avoid magic constants, such as the 4.65661287307739E-10 you had. I prefer to write them in a way that reveals what they stand for. Your value stems from 1.0/0x7FFFFFFF 3. I doubt the code you have shown would crash at all.
lat/(BEARING_SCALING * 180)
will not exceed the acceptable range for integers (and your formula being wrong by a factor of 2 IMO only reassures this).(positionData.msgPosLat) * BEARING_SCALING * 180)
may incur an integer overflow (again due to the factor of 2), but normally those get swallowed. So I expect if anything bombs, it must be the code that follows after you used these formulas, mainly the latitude going all the way up to +180. :)Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles] Nil Volentibus Arduum
Please use <PRE> tags for code snippets, and update CP Vanity to V2.0 if you haven't already.
modified on Thursday, December 9, 2010 3:45 PM
-
Thanks Luc, the Longitude (-180 to +180) has the same scaling. I can get the code running OK on Windwos but when ported to Unix (using a Gnu complier) the program bombs out. Debuggin a bit limited hence the use of Windows for the development.
Andy202 wrote:
the Longitude (-180 to +180) has the same scaling.
not sure what you are saying here. the longitude range has to cover 360 degrees (either -180 to +180 or 0 to +360), so it could be latitude uses the same scale factor, but then your opening statement (about MIN and MAX) isn't accurate for latitude. OTOH if the scale factor is different for lat and lon, that would justify why the 180 (or 360) isn't incorporated in the magic constant.
Andy202 wrote:
when ported to Unix (using a Gnu complier) the program bombs out.
A different compiler may generate different code, e.g. it could emit code that does check for overflows at run-time. [ADDED] So far you have not specified where in the code it crashes. [/ADDED] I can only suggest you: 1. include some logging statements so you can watch the numbers till the program crashes. 2. perform some unit tests (a simple loop over the range of interest should be easily implemented). Taken together, that will clarify what goes on. :)
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles] Nil Volentibus Arduum
Please use <PRE> tags for code snippets, and update CP Vanity to V2.0 if you haven't already.
modified on Thursday, December 9, 2010 5:17 PM
-
I have seen the term Fixed_32 for a data item with MSB = 1 and LSB = 1/2**31 ; Max = 1.0 and Min = -1.0 with units of semicircles (used for Latitude and Longitude) I did think this was a float to the IEEE-754 Floating-Point Representation. However the 3rd party that is reading some data via a message structure cannot see the same value. I mistaken the term Fixed_32 as a standard float but it is a 32 bit int in the message. The scalling is:-
#define BEARING_SCALING 4.65661287307739E-10
typedef struct ReceiveMessage
{
unsigned int msgNumber; // Msg number
int msgPosLat; // Msg latitude
int msgPosLong; // Msg longitude
unsigned int msgQuality; // Msg quality
}positionData#define BEARING_SCALING 4.65661287307739E-10
However I get a crash when I try to load the value (the Latitude was declared as a double and I tried to cast to the int and vice versa. Code:
// Note 180 is used to scale up from semicircles to degrees
double lat = 55.55;
positionData.msgPosLat = (int)(lat/(BEARING_SCALING * 180));// and the other way for reading:-
lat = (double)( positionData.msgPosLat) * BEARING_SCALING * 180;
What is going wrong please, is it the oder of casting or do I need to use fix point stuff?
normally c-compilers cast from left to right (implicit). if yours don't - cast yourself (explicit): positionData.msgPosLat = (int)(lat/(BEARING_SCALING * 180.0)); // (int)(double/(double*double)) AND lat = ( (double)positionData.msgPosLat * (BEARING_SCALING * 180.0)); // (double*(double*double)) // hint: don't define twice (BEARING_SCALING) have a nice day.