In previous posts we’ve seen how we can convert whole numbers from decimal to binary notation and back again but in all my posts so far we’ve only looked at integer (or whole) numbers. What if we wanted to represent real numbers instead? What if we wanted to represent numbers with fractional parts? In todays post we take a look at binary and decimal fractions.
Let’s look at an example using the decimal number 345.67810.
As you know, when we write a number in decimal, we can break it down into a number of different components:
|Number Base as Power|
As we saw with integer numbers, we have different columns on the left hand side of the decimal point that represent different components of the integer part of our number.
In this case though, on the right hand side of the decimal point we also have our fractional parts. As you can see the fractional part is also made up of a number of different columns representing fractional components of different sizes.
What you might not have realised is that just as the exponent (the number by which our number base or radix is raised) is reduced by one as we moved from left to right toward the decimal point, that trend continues on the right-hand side of the decimal point.
As our exponent becomes negative we get fractions and in the case of decimal this results in the 10ths, 100ths, 1000ths columns and so forth.. (As a side note, for those who are a bit rusty with their maths remember that 10-n is exactly the same as writing 1/10n).
The Radix Point
So given this, lets take a look at a similar example in binary. The first thing to mention here is that we need to correct some terminology.
In the description I gave above, I called the separator between the integer and fractional parts of the number the decimal point. In this next example though we’re not representing numbers as decimal, we’re going to be using binary, so what do we call this separator?
Well, as I’ve mentioned previously, an alternative name for the number base of a particular notation is the radix. So although the term decimal point is correct (at least for decimal), the more accurate term to use is the radix point (http://en.wikipedia.org/wiki/Radix_point). I’ll try and use that terminology as we move forwards.
So getting back to our example. Say we wanted to represent the binary fraction 101.1012 in decimal. Well, we could first break it down into its constituent components as follows:
|Number Base as Power|
Notice how the exponent turns negative to the right-hand side of the radix point just as it does with decimal. Let’s see if we can now take our binary fraction and convert it into its decimal equivalent.
Converting a Binary Fraction into a Decimal Fraction
The process of converting a binary fraction into its decimal equivalent is really two-fold and we’ll deal with the numbers the the left-hand and right-hand sides of the radix point separately.
To get started lets look at the left-hand side.
When looking at converting the binary on the left-hand side of the radix point we convert it just as we would when converting any binary integer number into its decimal equivalent. We do this by adding the results from each of the different number columns:
1012 = (1 * 22) + (0 * 21) + (1 * 20)
1012 = (1 * 4) + (0 * 2) + (1 * 1) = 510
Next, lets look at the right-hand side of the radix point. We do exactly the same thing here as we did on the left, just with the fractional columns:
0.1012 = (1 * 2-1) + (0 * 2-2) + (1 * 2-3)
0.1012 = (1 * 1/2) + (0 * 1/4) + (1 * 1/8)
0.1012 = (1 * 0.5) + (0 * 0.25) + (1 * 0.125) = 0.62510
So we have a fractional part that represents 0.62510.
All we have to do now is to combine the integer part and fractional parts together on either side of the radix point. This gives us the number 5.62510.
Converting from a Decimal Fraction to a Binary Fraction
Now what if we wanted to go the other way, from decimal to binary? I this next example, we’re going to take a decimal fraction and find it’s binary equivalent. This time we’re going to use 9.12510 and again deal with the left-hand side of the radix point first.
Calculating the Whole Number Part
Step one is to find the highest factor of 2 that will fit into the integer part of our number.
If we look through the different binary number columns above we can see that the highest factor that fits would be 8 (or 23) so we put a 1 in the 8’s column and subtract the value of that column (810) from our original number (910) and make a note of the reminder (110).
We then look at the 4’s column and see if that fits into our remainder. It doesn’t, so we put a 0 in that column.
We then look at the 2’s column and again the value of that column (210) doesn’t fit into our remainder (110) so again we put a 0 in that column. Finally we check the 1’s column.
With the 1’s column, the value of the column (110) does actually fit into our reminder (110) so we put a 1 in that column and again subtract the value of the column (110) from our remainder (110) to get a new remainder (010). This time we have a remainder of 0 so at this point we are done.
With that we have:
910 = (1 * 8) + (0 * 4) + (0 * 2) + (1 * 1) = 10012
910 = (1 * 23) + (0 * 22) + (0 * 21) + (1 * 20) = 10012
Calculating the Fractional Part
Next we need to deal with the fractional part of our decimal number (which as a reminder is 0.125).
Again, there is a simple step-by-step method for performing the conversion.
To begin with we take the decimal fraction and multiply it by two (i.e. 210 * 0.12510 = 0.25010). We then take the whole number part of the result as the first binary digit after the radix point. In this case it is 0 so we’ve got as far as 0.12510 = 0.0?2
Next we disregard the whole number part of the previous result (i.e. ignore the 0 before the radix point) and multiply the result by two again.
The whole number part of this new result is the second digit after the radix point (i.e. 210 * 0.25010 = 0.5010).
In this case, the whole number part is again a 0 so we’ve now got as far as 0.12510 = 0.00?2
Again, disregarding the whole number part of the result and again multiply by 2 (i.e. 210 * 0.5010 = 1.010).
Again we take the whole number part, this time as the value of the third digit after the radix point. In this case the whole number part is a 1 so we have now got to 0.12510 = 0.001?2
Again we drop the whole number part but as the fractional part we have left is 0. As we have nothing left we are done.
This leaves us with our final representation; 0.12510 is exactly equivalent to 0.0012.
Now that we have extracted both the integer part of our original number and the fractional part we can finally combine them on either side of the radix point:
9.12510 = 1001.0012
Whilst binary and decimal fractions both work on the same principles, each has their own problems when it comes to representing numbers accurately with a given number of digits.
In both cases there are certain numbers that will always result in something called a rounding error, where the number can’t be represented exactly and the nearest number has to be used instead.
For example, decimal notation has a problem representing the fraction ⅓ accurately. ⅓ in decimal is actually 0.3333 infinitely recurring (i.e. the 3’s continue forever after the decimal point).
When we represent ⅓ in decimal using a fixed number of decimal places we therefore get a rounding error, the representation of ⅓ is never completely accurate.
Similar situations occur with binary. If you try and represent a fraction where the denominator (the bit below the line in the fraction) is not a power of 2 you will also get a rounding errors with a given number of digits.
This is the case when we take most finite decimal fractions, i.e. fractions that can be accurately represented in decimal such as 1/10, and try to express them as binary fractions. Instead of being a finite fraction as it is in decimal fractions such as 1/10 are infinitely recurring when expressed as binary.
Watch out for this when you use binary fractions in your programs.