Convert 2s complement to whole and fractional parts?

Discussion in 'Embedded Systems and Microcontrollers' started by spinnaker, Jan 24, 2015.

  1. spinnaker

    Thread Starter AAC Fanatic!

    Oct 29, 2009
    4,884
    1,005
    I have a value in a buffer that represents a fractional 2s compliment number.

    For example:
    0000 0000 0000 1000 = +.05
    0000 0000 1010 0010 = +10.125

    I can convert them simple type setting a double to the buffer.

    But I would like to avoid using floating point. I would like to break them into two separate integers.

    .05
    whole = 0
    fraction = 5

    10.25
    whole=10
    fraction=125

    Or convert them to a string without using floating point

    Any idea how to do this?
     
  2. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,387
    1,605
    Move the binary point in your calculations to avoid the fractional part.

    That is equivalent to picking the units you work in, say using mA over amps. Note you are not limited to intervals of 3 in powers.
     
  3. WBahn

    Moderator

    Mar 31, 2012
    17,743
    4,792
    I don't see how you can get +.05 in a fixed point system since that is 1/20 which is not even exactly representable in binary.

    I have no idea what that last statement means. Could you give an example?

    How is "fraction" of .05 equal to 5?

    How is "fraction" of 10.25 equal to 125?

    Don't you at least need a consistent denominator? In the first one your denominator is 100 and in the second it is 500.

    What do you want in the string?

    To get two integers, then you can do that by simple bit banging. To get the whole part just shift the value to the right equal to the number of fractional bits. To get the fractional part use a mask that has 0s to the left of the radix point and 1s to the right and then AND it with the original (there is another simple way to do it, too). The fractional part is the numerator with the denominator being 2^n where n is the number of fractional bits. If you want to convert that to, say, the numerator where the denominator is a power of ten, then multiply by the denominator you want and then right shift it by the number of fractional bits.

    So let's assume there are four fractional bits and you want the result to be the numerator where the fraction is 1000.

    Code (Text):
    1.  
    2. 0000 0000 1010 0010  value
    3. 0000 0000 0000 1010  whole = value >> 4
    4.  
    5. 0000 0000 1010 0010  value
    6. 0000 0000 0000 1111  mask
    7. 0000 0000 0000 0010  frac = value & mask
    8.  
    9. 0000 0111 1101 0000  frac *= 1000 (base 10)
    10. 0000 0000 0111 1101  frac >>= 4
    11.  
    whole = 10
    frac = 125
     
  4. spinnaker

    Thread Starter AAC Fanatic!

    Oct 29, 2009
    4,884
    1,005

    I did not think to put a whole number in an integer. That would work too. I would just need to output the location of the

    Here is how I am converting now.

    1f((value[1]) & 0xff == 0xff)
    {
    d = -(((~value[0]) +1) /2.0);
    }
    else
    {
    d = value[0];
    d = (d / 2.0);
    }
    Seems to work for me as long as my values don't exceed 8 bits




    What I wanted to return in a string, if the result was decimal point I guess.
     
    Last edited: Jan 24, 2015
  5. spinnaker

    Thread Starter AAC Fanatic!

    Oct 29, 2009
    4,884
    1,005
    These numbers are from the examples in the DS18B20 datasheet.

    The one example makes sense

    125 = 0000 0111 1101 0000

    But the fractional ones are throwing me.
     
  6. spinnaker

    Thread Starter AAC Fanatic!

    Oct 29, 2009
    4,884
    1,005
    Ah ok was not looking at the data sheet close enough. I did not see the little -1

    upload_2015-1-24_20-25-4.png

    I am guessing the is the fractional part of the number. I am going to look at the samples gain.
     
  7. WBahn

    Moderator

    Mar 31, 2012
    17,743
    4,792
    Please use code tags and format your code. I'm assuming that that's an "if" on the first line, and not some function named "f()":

    Code (Text):
    1.  
    2. if((value[1]) & 0xff == 0xff)
    3. {
    4.   d = -(((~value[0]) +1) /2.0);
    5. }
    6. else
    7. {
    8.   d =  value[0];
    9.   d = (d  / 2.0);
    10. }
    11.  
    What's value[1] and value[0]? We aren't mind readers!

    You if() condition is only TRUE if the last four bits of value[1] are all 1s. Is that really what you want?

    Why does a test on value[1] control what you do with value[0]? Again, we don't know what these two values are and how they relate to one another.
     
  8. WBahn

    Moderator

    Mar 31, 2012
    17,743
    4,792
    Uh... yeah! That's what a fractional 2's complement representation means. It's also known as fixed point.
     
  9. spinnaker

    Thread Starter AAC Fanatic!

    Oct 29, 2009
    4,884
    1,005
    The example

    +10.125 = 0000 0000 1010 0010

    Makes sense for the whole number part. 1010 = 10. I don't see where they are getting 125 out of the lower 4 bits.

    Nor

    0.5 = 0000 0000 0000 1000
     
  10. WBahn

    Moderator

    Mar 31, 2012
    17,743
    4,792
    It would be nice if you linked the data sheet instead of making us search for it hoping to find the same one you are looking at.

    http://datasheets.maximintegrated.com/en/ds/DS18B20.pdf

    When I look at page 4, I do not see the same numbers you posted. I see +0.5 (not +.05) and I see +10.125 (not +10.25, as you use in the second part of your OP).
     
  11. MrChips

    Moderator

    Oct 2, 2009
    12,440
    3,361
    I wonder if you made a mistake here:
    Here is what I would have expected:
    You don't have to split it into whole numbers and fraction. What you have is called fixed point representation.
    I very rarely use floating point arithmetic in embedded systems
     
  12. WBahn

    Moderator

    Mar 31, 2012
    17,743
    4,792
    Did you look at the example where I worked through this?

    The rightmost bit has a weighting of 2^-4 which is 1/16
    The next bit has a weighting of 2^-3 which is 1/8
    The next bit has a weighting of 2^-2 which is 1/4
    The next bit has a weighting of 2^-1 which is 1/2

    So 0010 in the last four is

    0/2 + 0/4 + 1/8 + 0/16 = 1/8 = 0.125

    And 1000 in the last four is

    1/2 + 0/4 + 0/8 + 0/16 = 1/2 = 0.5
     
  13. spinnaker

    Thread Starter AAC Fanatic!

    Oct 29, 2009
    4,884
    1,005

    Sorry having issues with copy and paste out of the pdf. And a hassle of transferring the numbers with one small screen


    But I don't see how the fractional part works. Looking for fixed point info now, I know I have done this in the past long ago somewhere.
     
  14. MrChips

    Moderator

    Oct 2, 2009
    12,440
    3,361
    Look at WBahn's post #12. That should be clear enough. If not, ask again.
     
  15. spinnaker

    Thread Starter AAC Fanatic!

    Oct 29, 2009
    4,884
    1,005

    OK I get it now. So each bit in the fractional part actually represents a fraction.

    So is there an easy way to convert that to a value I can display? I have some ideas of just checking if each bit is set and add 500, 250 etc. accordingly

    So .5 = 500 + 0 + 0 = 500.
     
  16. MrChips

    Moderator

    Oct 2, 2009
    12,440
    3,361
    Before we get into that, how many digits do you want to display? How many places after the decimal point?

    Note that the value of the binary string taken as a whole is a decimal value that has been multiplied by 16.
     
    Last edited: Jan 24, 2015
  17. WBahn

    Moderator

    Mar 31, 2012
    17,743
    4,792
    The basic idea behind a fixed point system can be view at from two different -- and equivalent -- perspectives. The first is that you have a radix point (or binary point, which serves the exact same purpose as a decimal point, namely separating the whole part from the fractional part). The second is that you take a real number and scale it so that the fractional information you want is contained in the whole part and then you do all of your work with the integers.

    For instance, in banking it is quite common to only work with integers to represent dollar amounts in cents. This is accomplished simply by multiplying all money amounts, such as $1.98, by 100 so that you are working with 198 (note: they scale it up more, but this gets the idea across). You can then work with integers and, at the end, simply divide by 100 to get things back.

    For a binary fixed point system you multiply by powers of two. Just as multiplying by ten in a decimal system moves the decimal point one place to the right, multiplying by two in a binary system moves the radix point one bit to the right.

    So take a value like 10.125 and multiply it by 16 (four places) and you get 162. What is the binary representation of the integer 162? Compare that to the entry for 10.125 in the data sheet.
     
  18. WBahn

    Moderator

    Mar 31, 2012
    17,743
    4,792
    I showed you how to do that (for three decimal places) in detail in Post #3.

    If you want two places, then multiply by 100. If you want four places, then multiply by 10000. If you want N places, then multiply by 10^N.

    There are other ways to do it as well, depending on how you are converting integers to strings.
     
  19. MrChips

    Moderator

    Oct 2, 2009
    12,440
    3,361
    WBahn and I are cross posting. But we are both showing you the same thing.
    If you want to display two decimal places, multiply the number by 100 and divide by 16.
    All you have to do is display the result and insert decimal point before the last two digits.
    If you want to implement rounding correctly I will show you how to do that.
     
  20. spinnaker

    Thread Starter AAC Fanatic!

    Oct 29, 2009
    4,884
    1,005

    Ah OK I see it now. The table thing through me a little. Wow that is easy! Thanks for the help and sorry for being so dense. I will blame it on the beer. :)
     
Loading...