|
|
View previous topic :: View next topic |
Author |
Message |
ljbeng
Joined: 10 Feb 2004 Posts: 205
|
Double Precision Float |
Posted: Thu Jul 19, 2007 10:24 am |
|
|
I don't need any DOUBLE precision float for any math functions in the PIC chip. I only need it to program the base of a GPS receiver.
If I have a (4 byte) floating point number such as 40.345333, I need to convert that to an 8 byte double precision, only to send to the serial port of the GPS receiver. Is there a method to do this? I need to experiment with trying this, it may not work if the base does not like the precison of converting a single to double.
I have 3.249 and a PIC18F2620. |
|
|
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Thu Jul 19, 2007 11:15 am |
|
|
Is the GPS looking for binary bytes or ascii digits? I would approach this as a string manipulation problem. _________________ The search for better is endless. Instead simply find very good and get the job done. |
|
|
Douglas Kennedy
Joined: 07 Sep 2003 Posts: 755 Location: Florida
|
|
Posted: Thu Jul 19, 2007 12:08 pm |
|
|
Quote: | f I have a (4 byte) floating point number such as 40.345333 |
This has 8 significant decimal digits and will never be expressed without approximation in a 23 bit mantissa. Remember numbers exist on their own in this universe and what we take to be a number is merely a notational representation of its existence. For Navigation the notation is deg,mins and seconds or possibly in your case seconds extended to 2 decimal places or maybe degs.nnnnnn. You then further encode this in a floating point representation of your deg,min,sec notation. This may often cause a notational loss of accuracy and this may well be why you seek to an 8 byte floating pt representation. It is far easier to avoid errors from notation within notation issues by either using a string to notate the value
"40345333" 8 bytes with an implied decimal point or keep degs mins and seconds in integer fields. Ex deg int8, mins int8 and seconds int16 with an implied decimal pt ( 4 bytes total). The loss of information you are seeing is a result of binary versus decimal notation and a finite bit space for the exponent and the mantissa. The value 1/3 cannot be expressed accurately in binary notation or even decimal notation yet the string "1/3" captures its value accurately. This often called rounding but strictly speaking rounding is a choice to leave details out but this rounding is unavoidable short of changing the notational base to 3 to express 1/3 as 0.1 base 3 |
|
|
ljbeng
Joined: 10 Feb 2004 Posts: 205
|
|
Posted: Thu Jul 19, 2007 1:41 pm |
|
|
I am not looking for accuracy.
The instructions of the GPS receiver say it must receive a Double Precision, 8 byte representation of the latitude 40.123456. The accuracy of the latitude is +-30ft so the value does not need to be 16 decimal points accurate. I just need to convert the number from a 4 byte floating to an 8 byte floating. |
|
|
Ttelmah Guest
|
|
Posted: Thu Jul 19, 2007 3:08 pm |
|
|
You will need to do a little more, since I'd expect the device to want IEEE floats, rather than PIC floats.
Basically, you will have to extract the 23bit mantissa, sign bit, and 8 bit exponent from the PIC format, then on the exponent, add 896 (the 8 bit format uses a 1023 offset value, while the 11 bit format uses 127), and put the bits into the required locations in the 8 byte result...
It is not too complex to do, since (fortunately), except for adjusting the exponent, and re-arranging the data, you can just extend the mantissa with 0's.
It depends a lot on whether you want a really fast and neat way of doing this, or are prepared to accept simpler code, at a cost in performance?.
Now, no warranties on this, probably have the bit orders all wrong... :
Code: |
struct data {
int8 b[8]
};
union access {
int8 b[4];
float fp;
};
struct data convert_to_eight(union access val) {
int16 temp;
int1 sign;
int8 ctr;
stuct data result;
temp=make16(0,val.b[0]);
temp+=896;
//temp is now the 11bit exponent required
temp<<=4;
//move left 4 bits.
sign=bit_test(val.fp,8); //sign bit
val.b[0]=0;
bt_clear(val.fp,8);
//shift the bytes left 5 bits
for (ctr=0;ctr<5;ctr++) shift_left(&val.fp,4,0);
//fill with zeros
for (ctr=0;ctr<8;ctr--) result.b[ctr]=0;
//now transfer the 23bit mantissa
for (ctr=0;ctr<4;ctr++) result.b[ctr+1]=val.b[ctr];
//put in the sign bit
if (sign) bit_set(result.b[0],7);
//Now need to move in the exponent, without damaging what is there
result.b[0]|=make8(temp,1); //I think this is the right byte...
result.b[1]|=make8(temp,0);
return(result);
}
|
This will almost certainly be well wrong. You will need to test with a known 32bit FP value, against some know required outputs. However the basic 'idea' is sound. You have to extract the 8bit exponent into a 16bit value, and add 896. Then because this is offset by four bits in the output, shift this to the required spot. Then you have to move the mantissa left (filling both sides with zeros), and put the whole thing back together...
The result, will be an eight byte aray containing the bytes, and the function is called with the PIC FP value.
Best Wishes |
|
|
ljbeng
Joined: 10 Feb 2004 Posts: 205
|
|
Posted: Thu Jul 19, 2007 3:55 pm |
|
|
Thanks, I will start there.
Yes I can compare known good DP floats and the SP float.
Thanks. |
|
|
Ken Johnson
Joined: 23 Mar 2006 Posts: 197 Location: Lewisburg, WV
|
|
Posted: Thu Jul 19, 2007 5:49 pm |
|
|
Look at ieeefloat.c in the drivers folder. Only does 32-bit, but that's a start. Shouldn't be too difficult to extend to 64-bit, maybe
Ken |
|
|
ljbeng
Joined: 10 Feb 2004 Posts: 205
|
|
Posted: Fri Jul 27, 2007 7:26 am |
|
|
Good Old Wikepedia explained single and double very nicely.
This only converts a 4 byte single floating to an 8 byte double floating but does not increase the accuracy of the number. This just merely rearranges the bits to match the double bit pattern.
Code: | void cvd(int32 vl) {
int sign;
int32 exp;
int32 b1,b2,b3;
sign = bit_test(vl,31);
exp = (int32)vl >> 23;
exp &= 0xff;
exp += 896;
b1 = vl & 0x7fffff;
b1 = b1 << 9;
b2 = exp << 20;
if (sign) bit_set(b2,31);
b2 += b1>>12;//ms 4 bytes
b3 = b1 << 20;//ls 4 bytes
}
|
|
|
|
|
|
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
|