glen herrmannsfeldt <gah@ugcs.caltech.edu> writes:> Randy Yates <yates@digitalsignallabs.com> wrote: > > (snip) >>>> It's a Q2.12 (note I would denote this as an A(1, 12)). The maximum >>>> positive scaled (unscaled) value is 2 - 1/4096 (8191), and the minimum >>>> negative scaled (unscaled) value is -2 (-8192). > >>>> To get the scaled value x from the unscaled value X, >>>> divide by 2^12 = 4096: > >>> But the original question is how to make a decimal fraction >>> out of it. > >> You mean with a computer program (as opposed to, e.g., on your >> calculator)? > > Yes. > >> Wouldn't > >> double DecimalFraction(int16_t x) >> { >> return x / 4096.0; >> } > >> do it (where x is the Q2.12 input value)? > > That converts, at least on most machines, to a binary floating > point value. > > For machines supporting IEEE 754-2008, that could be decimal > float, but usually I expect to convert to fixed decimal. > > Since 12 bits are about four decimal digits, you might convert > to a fixed point decimal value with four digits after the decimal > point. > > If you mulitiply x by 10000, then divide by 4096, you have > the integer value of 1/10000ths (truncated) of the quantity in x. > > For a more common example, multiply x by 100, integer divide by 4096, > and if X is in dollars and binary fractions of dollars, you get the > value as an integer number of cents. Add 2048 before the divide > to get the rounded up value. > > int x,y > x=123456; /* that is 123456/4096ths */ > y=(x*100)/4096; > printf("%d.%02d\n",y/100, y%100); > > Analogous to the Q2.13 form, the y value has two decimal digits > after the decimal point, even when stored as a binary value. > > (PL/I would call it FIXED DECIMAL(5,2), where X might > be FIXED BIN(15,12)). > > -- glenglen, I think this is WAY over-complicating things and not at all what the OP wanted. I think he said "decimal" but really meant "float." -- Randy Yates Digital Signal Labs http://www.digitalsignallabs.com
Datasheet Question
Started by ●August 26, 2015
Reply by ●August 28, 20152015-08-28
Reply by ●August 28, 20152015-08-28
Randy Yates <yates@digitalsignallabs.com> writes:> Mauritz Jameson <mjames2393@gmail.com> writes: > >> So do everybody agree that the PDF states that the 2 bytes together form a Q2.12 number and *this*: >> >> double x = ((double) ((((int16_t)(MSB << 8)) | LSB) >> 2)) / 4096.0; >> >> is how the two bytes should be interpreted (as a double value) ? >> >> (I guess I'm having a hard time asking the right question) > > I don't think that's right. I would say this: > > double x = ((double) ((((int16_t)(MSB << 6)) | LSB) >> 2)) / 4096.0;This is not right either - the MSB won't be sign-extended. But I think this would work: double x = ((((int16_t)MSB << 8) | LSB) >> 2) / 4096.0; Note that the (double) typecast in the original expression from the datasheet is not necessary due to the default double type of the constant 4096.0 and C's promotion rules. -- Randy Yates Digital Signal Labs http://www.digitalsignallabs.com
Reply by ●August 28, 20152015-08-28
Randy Yates <yates@digitalsignallabs.com> writes:> Mauritz Jameson <mjames2393@gmail.com> writes: > >> So do everybody agree that the PDF states that the 2 bytes together form a Q2.12 number and *this*: >> >> double x = ((double) ((((int16_t)(MSB << 8)) | LSB) >> 2)) / 4096.0; >> >> is how the two bytes should be interpreted (as a double value) ? >> >> (I guess I'm having a hard time asking the right question) > > I don't think that's right.Ooops - Yes it is - I missed the parenthesis to the right of the "LSB". Sorry for the confusion. I do think the (double) typecast is unnecessary, though, as I explained in a subsequent follow-up. -- Randy Yates Digital Signal Labs http://www.digitalsignallabs.com
Reply by ●August 28, 20152015-08-28
> This is not right either - the MSB won't be sign-extended. But I think > this would work: > > double x = ((((int16_t)MSB << 8) | LSB) >> 2) / 4096.0; >Exactly! You have to shift 8 up to ensure sign extension when you later shift down by 2. So I guess you agree with me Randy :-) This is the expression I wrote in one of my earlier posts: double x = ((double) ((((int16_t)(MSB << 8)) | LSB) >> 2)) / 4096.0;
Reply by ●August 28, 20152015-08-28
Mauritz Jameson <mjames2393@gmail.com> writes:>> This is not right either - the MSB won't be sign-extended. But I think >> this would work: >> >> double x = ((((int16_t)MSB << 8) | LSB) >> 2) / 4096.0; >> > > > Exactly! You have to shift 8 up to ensure sign extension when you > later shift down by 2. So I guess you agree with me Randy :-)Yes, I do. -- Randy Yates Digital Signal Labs http://www.digitalsignallabs.com
Reply by ●August 28, 20152015-08-28
> > Wow, that is brain-damaged.Yeah, the description in the PDF is a bit awkward which is why I posted my question in this group (to get some clarification).
Reply by ●August 28, 20152015-08-28
Randy Yates <yates@digitalsignallabs.com> wrote: (snip, I wrote)>> For machines supporting IEEE 754-2008, that could be decimal >> float, but usually I expect to convert to fixed decimal.>> Since 12 bits are about four decimal digits, you might convert >> to a fixed point decimal value with four digits after the decimal >> point.>> If you mulitiply x by 10000, then divide by 4096, you have >> the integer value of 1/10000ths (truncated) of the quantity in x.>> For a more common example, multiply x by 100, integer divide by 4096, >> and if X is in dollars and binary fractions of dollars, you get the >> value as an integer number of cents. Add 2048 before the divide >> to get the rounded up value.>> int x,y >> x=123456; /* that is 123456/4096ths */ >> y=(x*100)/4096; >> printf("%d.%02d\n",y/100, y%100);(snip)> I think this is WAY over-complicating things and not at all what the OP > wanted. I think he said "decimal" but really meant "float."That could be, which is why I suggested float decimal. Otherwise, I don't see how to get them confused. But from what he is actually doing, you might be right. -- glen
Reply by ●August 28, 20152015-08-28
On 8/27/2015 9:50 PM, Mauritz Jameson wrote:> >> OK, why the >>2? >> >> Seems to me that loses the two low order bits. >> That, combined with the /4096, means 14 bits after the binary point, >> only 12 of them actually get into x. >> >> -- glen > > > The MSB byte has 8 bits of data where the most significant bit is the sign bit. > > The LSB byte has 6 bits of data where the most significant bit of those 6 bits is placed at bit 7 (counting from 0). > > So the logic behind the C-expression is: > > 1. Cast MSB to a 16-bit signed value and shift it up by 8 > 2. OR the LSB with the result of [1] > 3. Now we have a 14-bit value where the 2 least significant bits are 0 (remember that the LSB only had 6 bits of data) > 4. So shift the result of [2] down by 2 > 5. Typecast the result of [4] to a double > 6. Divide by 4096.0 (since it's a Q2.12 value) > > Does it make sense?Yes -- Rick
Reply by ●August 28, 20152015-08-28
On 8/27/2015 11:59 PM, Randy Yates wrote:> Mauritz Jameson <mjames2393@gmail.com> writes: > >>> This is not right either - the MSB won't be sign-extended. But I think >>> this would work: >>> >>> double x = ((((int16_t)MSB << 8) | LSB) >> 2) / 4096.0; >>> >> >> >> Exactly! You have to shift 8 up to ensure sign extension when you >> later shift down by 2. So I guess you agree with me Randy :-) > > Yes, I do.Not exactly. Randy's code converts MSB to a 16 bit quantity first, then shifts. Mauritiz's code shifts then type casts as a 16 bit quantity. If MSB is an 8 bit quantity shifting before converting type will lose all the data giving a zero value. -- Rick
Reply by ●August 28, 20152015-08-28
On 8/27/2015 11:59 PM, Mauritz Jameson wrote:>> >> Wow, that is brain-damaged. > > Yeah, the description in the PDF is a bit awkward which is why I posted my question in this group (to get some clarification).I think some people are stuck on the idea that all 16 bits read from the converter are data. The description is not so awkward as far as I can tell. -- Rick