Currently I'm in the process of replacing a custom compass / accelerometer with an ST LSM303D. The 'old' custom device produced single precision floats. Without parsing the values there where just passed inside a UDP packet. Unfortunately the LSM303D produces 16 bit signed integers. So, the embedded system needs to convert these values to floats. The scaling it self is quite simple: Values -32768..32767 need to be scaled to [-2,2). Now, my hardware has no floating point support. However doing the following: float output = ( (float)input ) / 16384f; will require quite a bit of FP magic. I would imagine that this: const float scale = 1f / 16384f; float output = ( (float)input ) * scale; may be faster, but still requires FP multiply support. Is there a simple and fast way which I can use to convert these integers to floats without the aid of an FP library? I have not found much code in this respect. Vincent
Integer/Fixedpoint to 32 bit float
Started by ●April 6, 2016
Reply by ●April 6, 20162016-04-06
On 06.4.2016 г. 16:17, Vincent vB wrote:> Currently I'm in the process of replacing a custom compass / > accelerometer with an ST LSM303D. The 'old' custom device produced > single precision floats. Without parsing the values there where just > passed inside a UDP packet. > > Unfortunately the LSM303D produces 16 bit signed integers. So, the > embedded system needs to convert these values to floats. The scaling it > self is quite simple: Values -32768..32767 need to be scaled to [-2,2). > > Now, my hardware has no floating point support. However doing the > following: > > float output = ( (float)input ) / 16384f; > > will require quite a bit of FP magic. I would imagine that this: > > const float scale = 1f / 16384f; > float output = ( (float)input ) * scale; > > may be faster, but still requires FP multiply support. > > Is there a simple and fast way which I can use to convert these integers > to floats without the aid of an FP library? I have not found much code > in this respect. > > Vincent >Of course there is, will cost a few operations. You can look up the IEEE 32 bit floating point format and figure out how to do it. Basically it will take several shifts left (you will have to count these) of your 16 bit integer until its MSB gets positioned as bit 23, subtract the count of shifts it took to get there from 150 ($96) and insert this result into bits 23 to 32 (this will overwrite the MSB which got to position 23). For negative input numbers, negate first, convert as above and set bit 31 of the final result to 1. Disclaimer: this is what I just made up at the moment by memory, I can't guarantee its correctness. It is meant to show you the direction, not to be a 1:1 algorithm you can use. You should understand the FP format yourself and figure out how to do it. Dimiter ------------------------------------------------------ Dimiter Popoff, TGI http://www.tgi-sci.com ------------------------------------------------------ http://www.flickr.com/photos/didi_tgi/
Reply by ●April 6, 20162016-04-06
On 06.4.2016 г. 17:16, Dimiter_Popoff wrote:> On 06.4.2016 г. 16:17, Vincent vB wrote: >> Currently I'm in the process of replacing a custom compass / >> accelerometer with an ST LSM303D. The 'old' custom device produced >> single precision floats. Without parsing the values there where just >> passed inside a UDP packet. >> >> Unfortunately the LSM303D produces 16 bit signed integers. So, the >> embedded system needs to convert these values to floats. The scaling it >> self is quite simple: Values -32768..32767 need to be scaled to [-2,2). >> >> Now, my hardware has no floating point support. However doing the >> following: >> >> float output = ( (float)input ) / 16384f; >> >> will require quite a bit of FP magic. I would imagine that this: >> >> const float scale = 1f / 16384f; >> float output = ( (float)input ) * scale; >> >> may be faster, but still requires FP multiply support. >> >> Is there a simple and fast way which I can use to convert these integers >> to floats without the aid of an FP library? I have not found much code >> in this respect. >> >> Vincent >> > > Of course there is, will cost a few operations. You can look up the > IEEE 32 bit floating point format and figure out how to do it. > Basically it will take several shifts left (you will have to count > these) of your 16 bit integer until its MSB gets positioned as bit > 23, subtract the count of shifts it took to get there from 150 ($96) and > insert this result into bits 23 to 32 (this will overwrite the > MSB which got to position 23). > For negative input numbers, negate first, convert as above and > set bit 31 of the final result to 1. > > Disclaimer: this is what I just made up at the moment by memory, > I can't guarantee its correctness. It is meant to show you the > direction, not to be a 1:1 algorithm you can use. You should > understand the FP format yourself and figure out how to do it. > > Dimiter > > ------------------------------------------------------ > Dimiter Popoff, TGI http://www.tgi-sci.com > ------------------------------------------------------ > http://www.flickr.com/photos/didi_tgi/ > > >Oops, sorry for the brain damaged "bits 23 to 32", it should read "bits 23 to 30" of course (my fingers here _again_ typed in 32 and I had to correct it.....).
Reply by ●April 6, 20162016-04-06
On 2016-04-06, Dimiter_Popoff <dp@tgi-sci.com> wrote:> On 06.4.2016 г. 16:17, Vincent vB wrote: >> Currently I'm in the process of replacing a custom compass / >> accelerometer with an ST LSM303D. The 'old' custom device produced >> single precision floats. Without parsing the values there where just >> passed inside a UDP packet. >> >> Unfortunately the LSM303D produces 16 bit signed integers. So, the >> embedded system needs to convert these values to floats. The scaling it >> self is quite simple: Values -32768..32767 need to be scaled to [-2,2). >> >> Now, my hardware has no floating point support. However doing the >> following: >> >> float output = ( (float)input ) / 16384f; >> >> will require quite a bit of FP magic. I would imagine that this: >> >> const float scale = 1f / 16384f; >> float output = ( (float)input ) * scale; >> >> may be faster, but still requires FP multiply support. >> >> Is there a simple and fast way which I can use to convert these integers >> to floats without the aid of an FP library? I have not found much code >> in this respect. >> >> Vincent > > Of course there is, will cost a few operations. You can look up the > IEEE 32 bit floating point format and figure out how to do it. > Basically it will take several shifts left (you will have to count > these) of your 16 bit integer until its MSB gets positioned as bit > 23, subtract the count of shifts it took to get there from 150 ($96) and > insert this result into bits 23 to 32 (this will overwrite the > MSB which got to position 23). > For negative input numbers, negate first, convert as above and > set bit 31 of the final result to 1.[Remember to check for a negative input value, convert it to positive, and then later set the sign bit in the FP result] That converts the value to FP. To scale it by factor of 2/32768 you should be able to simply subtract 14 from the exponent. Don't forget that the exponent is stored in an excess-127 representation (not 2's compliment or sign-magnitude). -- Grant Edwards grant.b.edwards Yow! I guess it was all a at DREAM ... or an episode of gmail.com HAWAII FIVE-O ...
Reply by ●April 6, 20162016-04-06
... and start by writing a C test program to debug/test on your desktop, where you have the float library available to compare against...
Reply by ●April 6, 20162016-04-06
Op 06-Apr-16 om 3:17 PM schreef Vincent vB:> Currently I'm in the process of replacing a custom compass / > accelerometer with an ST LSM303D. The 'old' custom device produced > single precision floats. Without parsing the values there where just > passed inside a UDP packet. > > Unfortunately the LSM303D produces 16 bit signed integers. So, the > embedded system needs to convert these values to floats. The scaling it > self is quite simple: Values -32768..32767 need to be scaled to [-2,2). > > Now, my hardware has no floating point support. However doing the > following: > > float output = ( (float)input ) / 16384f; > > will require quite a bit of FP magic. I would imagine that this: > > const float scale = 1f / 16384f; > float output = ( (float)input ) * scale; > > may be faster, but still requires FP multiply support. > > Is there a simple and fast way which I can use to convert these integers > to floats without the aid of an FP library? I have not found much code > in this respect.Reality check: what is the use of having the values in floating point format, if you want to avoid using an FP library? What are you going to do with those values? Wouter van Ooijen
Reply by ●April 6, 20162016-04-06
On Wed, 6 Apr 2016 14:40:49 +0000 (UTC), Grant Edwards <invalid@invalid.invalid> wrote:>On 2016-04-06, Dimiter_Popoff <dp@tgi-sci.com> wrote: >> On 06.4.2016 ?. 16:17, Vincent vB wrote: >>> Currently I'm in the process of replacing a custom compass / >>> accelerometer with an ST LSM303D. The 'old' custom device produced >>> single precision floats. Without parsing the values there where just >>> passed inside a UDP packet. >>> >>> Unfortunately the LSM303D produces 16 bit signed integers. So, the >>> embedded system needs to convert these values to floats. The scaling it >>> self is quite simple: Values -32768..32767 need to be scaled to [-2,2). >>> >>> Now, my hardware has no floating point support. However doing the >>> following: >>> >>> float output = ( (float)input ) / 16384f; >>> >>> will require quite a bit of FP magic. I would imagine that this: >>> >>> const float scale = 1f / 16384f; >>> float output = ( (float)input ) * scale; >>> >>> may be faster, but still requires FP multiply support. >>> >>> Is there a simple and fast way which I can use to convert these integers >>> to floats without the aid of an FP library? I have not found much code >>> in this respect. >>> >>> Vincent >> >> Of course there is, will cost a few operations. You can look up the >> IEEE 32 bit floating point format and figure out how to do it. >> Basically it will take several shifts left (you will have to count >> these) of your 16 bit integer until its MSB gets positioned as bit >> 23, subtract the count of shifts it took to get there from 150 ($96) and >> insert this result into bits 23 to 32 (this will overwrite the >> MSB which got to position 23). >> For negative input numbers, negate first, convert as above and >> set bit 31 of the final result to 1. > >[Remember to check for a negative input value, convert it to positive, >and then later set the sign bit in the FP result] > >That converts the value to FP. > >To scale it by factor of 2/32768 you should be able to simply subtract >14 from the exponent. > >Don't forget that the exponent is stored in an excess-127 >representation (not 2's compliment or sign-magnitude).Assuming you're starting with an IEEE float containing an integer -32768..32767, you can just subtract 14 from the exponent, *but* you have to handle zero as a special case. OTOH, that sounds like extra work, just convert it correctly in the first place. Starting with a 16 bit signed integer: 1. handle zero as a special case 2. consider handling -32768 as a special case 3. remove (and save) sign (IOW, take the absolute value) 4. count the number of leading zeros (lz) 4a. the result would be 1-15, 0-15 if you didn't special case -32768 5. put the result in a 32 bit unsigned integer 6. shift left (23-lz) places 7. set the 8 exponent bits (30-22) to (127+(15-lz)) 7a. note that this overlays one bit from step 6 7b. approximately: ui32 &= 0x007fffff; ui32 |= (127-(15-lz)) << 23; 8. set the sign bit (31) as appropriate Modulo bugs (I did the above from memory, but it should be close), that should then have a single precision float in the 32 bit unsigned integer, cast as needed. If you want to convert to a double, it's basically the same procedure, but some of the constants change.
Reply by ●April 6, 20162016-04-06
On Wed, 06 Apr 2016 12:33:35 -0500, Robert Wessel <robertwessel2@yahoo.com> wrote:>On Wed, 6 Apr 2016 14:40:49 +0000 (UTC), Grant Edwards ><invalid@invalid.invalid> wrote: > >>On 2016-04-06, Dimiter_Popoff <dp@tgi-sci.com> wrote: >>> On 06.4.2016 ?. 16:17, Vincent vB wrote: >>>> Currently I'm in the process of replacing a custom compass / >>>> accelerometer with an ST LSM303D. The 'old' custom device produced >>>> single precision floats. Without parsing the values there where just >>>> passed inside a UDP packet. >>>> >>>> Unfortunately the LSM303D produces 16 bit signed integers. So, the >>>> embedded system needs to convert these values to floats. The scaling it >>>> self is quite simple: Values -32768..32767 need to be scaled to [-2,2). >>>> >>>> Now, my hardware has no floating point support. However doing the >>>> following: >>>> >>>> float output = ( (float)input ) / 16384f; >>>> >>>> will require quite a bit of FP magic. I would imagine that this: >>>> >>>> const float scale = 1f / 16384f; >>>> float output = ( (float)input ) * scale; >>>> >>>> may be faster, but still requires FP multiply support. >>>> >>>> Is there a simple and fast way which I can use to convert these integers >>>> to floats without the aid of an FP library? I have not found much code >>>> in this respect. >>>> >>>> Vincent >>> >>> Of course there is, will cost a few operations. You can look up the >>> IEEE 32 bit floating point format and figure out how to do it. >>> Basically it will take several shifts left (you will have to count >>> these) of your 16 bit integer until its MSB gets positioned as bit >>> 23, subtract the count of shifts it took to get there from 150 ($96) and >>> insert this result into bits 23 to 32 (this will overwrite the >>> MSB which got to position 23). >>> For negative input numbers, negate first, convert as above and >>> set bit 31 of the final result to 1. >> >>[Remember to check for a negative input value, convert it to positive, >>and then later set the sign bit in the FP result] >> >>That converts the value to FP. >> >>To scale it by factor of 2/32768 you should be able to simply subtract >>14 from the exponent. >> >>Don't forget that the exponent is stored in an excess-127 >>representation (not 2's compliment or sign-magnitude). > > >Assuming you're starting with an IEEE float containing an integer >-32768..32767, you can just subtract 14 from the exponent, *but* you >have to handle zero as a special case. > >OTOH, that sounds like extra work, just convert it correctly in the >first place. Starting with a 16 bit signed integer: > >1. handle zero as a special case >2. consider handling -32768 as a special case >3. remove (and save) sign (IOW, take the absolute value) >4. count the number of leading zeros (lz) > 4a. the result would be 1-15, 0-15 if you didn't special case -32768 >5. put the result in a 32 bit unsigned integer >6. shift left (23-lz) places >7. set the 8 exponent bits (30-22) to (127+(15-lz)) > 7a. note that this overlays one bit from step 6 > 7b. approximately: > ui32 &= 0x007fffff; > ui32 |= (127-(15-lz)) << 23; >8. set the sign bit (31) as appropriate > >Modulo bugs (I did the above from memory, but it should be close), >that should then have a single precision float in the 32 bit unsigned >integer, cast as needed. If you want to convert to a double, it's >basically the same procedure, but some of the constants change.And duh, subtract the 14 in step 7 above...
Reply by ●April 6, 20162016-04-06
On 2016-04-06, Robert Wessel <robertwessel2@yahoo.com> wrote:> [16-bit signed to IEEE single conversion algorithm]And then write a test program that tests and verifies the conversion function for all 65536 possible input values. You could try to figure out a minimal set of inputs that provides 100% test coverage, but a) you'll be wrong[*] b) with only a 16-bit input space, it'll be faster and easier to just test all possible inputs [*] At least that's been my experience with stuff like this. -- Grant Edwards grant.b.edwards Yow! Now that I have my at "APPLE", I comprehend COST gmail.com ACCOUNTING!!
Reply by ●April 6, 20162016-04-06
On 6.4.16 19:00, Wouter van Ooijen wrote:> Op 06-Apr-16 om 3:17 PM schreef Vincent vB: >> Currently I'm in the process of replacing a custom compass / >> accelerometer with an ST LSM303D. The 'old' custom device produced >> single precision floats. Without parsing the values there where just >> passed inside a UDP packet. >> >> Unfortunately the LSM303D produces 16 bit signed integers. So, the >> embedded system needs to convert these values to floats. The scaling it >> self is quite simple: Values -32768..32767 need to be scaled to [-2,2). >> >> Now, my hardware has no floating point support. However doing the >> following: >> >> float output = ( (float)input ) / 16384f; >> >> will require quite a bit of FP magic. I would imagine that this: >> >> const float scale = 1f / 16384f; >> float output = ( (float)input ) * scale; >> >> may be faster, but still requires FP multiply support. >> >> Is there a simple and fast way which I can use to convert these integers >> to floats without the aid of an FP library? I have not found much code >> in this respect. > > Reality check: what is the use of having the values in floating point > format, if you want to avoid using an FP library? What are you going to > do with those values? > > Wouter van OoijenThe OP said that the rest of the system expects the direction values in single-precision floating point format. -- -TV







