Convert 2s complement to whole and fractional parts?

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
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?
 

ErnieM

Joined Apr 24, 2011
8,377
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.
 

WBahn

Joined Mar 31, 2012
30,076
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 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 can convert them simple type setting a double to the buffer.
I have no idea what that last statement means. Could you give an example?

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
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.

Or convert them to a string without using floating point

Any idea how to do this?
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:
0000 0000 1010 0010  value
0000 0000 0000 1010  whole = value >> 4

0000 0000 1010 0010  value
0000 0000 0000 1111  mask
0000 0000 0000 0010  frac = value & mask

0000 0111 1101 0000  frac *= 1000 (base 10)
0000 0000 0111 1101  frac >>= 4
whole = 10
frac = 125
 

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
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:
0000 0000 1010 0010  value
0000 0000 0000 1010  whole = value >> 4

0000 0000 1010 0010  value
0000 0000 0000 1111  mask
0000 0000 0000 0010  frac = value & mask

0000 0111 1101 0000  frac *= 1000 (base 10)
0000 0000 0111 1101  frac >>= 4
whole = 10
frac = 125

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:

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
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.
 

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
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.
 

WBahn

Joined Mar 31, 2012
30,076
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.

f((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.
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:
if((value[1]) & 0xff == 0xff)
{
  d = -(((~value[0]) +1) /2.0);
}
else
{
  d =  value[0];
  d = (d  / 2.0);
}
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.
 

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
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
 

WBahn

Joined Mar 31, 2012
30,076
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.
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).
 

MrChips

Joined Oct 2, 2009
30,823
I wonder if you made a mistake here:
For example:
0000 0000 0000 1000 = +.05
0000 0000 1010 0010 = +10.125
Here is what I would have expected:
For example:
0000 0000 0000 1000 = +.5
0000 0000 1010 0010 = +10.125
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
 

WBahn

Joined Mar 31, 2012
30,076
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
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
 

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
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).

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.
 

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
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

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.
 

MrChips

Joined Oct 2, 2009
30,823
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:

WBahn

Joined Mar 31, 2012
30,076
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.
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.
 

WBahn

Joined Mar 31, 2012
30,076
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.
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.
 

MrChips

Joined Oct 2, 2009
30,823
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.
 

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
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.

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. :)
 
Top