If I hadn't studied floating point from here my answer would be fraction bits of 000…000 and exponent value of −1 as shown below : But in the link I attached above, they mention Denormalized value in which case my answer for this question would be fraction bits of 100…000 and exponent value of 0. I know I'm mixing something up, and the second answer is probably wrong. Can somebody please clarify why it can't be denormalised value?
-
1\$\begingroup\$ Look at the range of denormalised numbers given in the linked document, and determine for yourself whether or not 0.5 is within that range. \$\endgroup\$– user16324Commented Jan 12, 2018 at 18:03
-
\$\begingroup\$ Where do I hide myself. Thank you though! Big help, been beating myself over this. Sigh. @BrianDrummond \$\endgroup\$– momoCommented Jan 12, 2018 at 18:37
2 Answers
Start with the number you have as \$v\$ and the number of mantissa bits available in the format as \$m=23\$ (for this format.) Assuming that \$v\ne 0\$, apply the following logic:
- Set up a new variable as \$p=0\$.
- if \$v\$ is positive, set \$s=0\$ else set \$v=\:\mid v \:\mid\$ and \$s=1\$.
- while \$v\lt 2^m\$, set \$p=p-1\$ and \$v=2\cdot v\$.
- while \$v\ge 2^{m+1}\$, set \$p=p+1\$ and \$v=\frac{v}{2}\$.
At this point, you have a value \$v : 2^m\le v\lt 2^{m+1}\$. The magnitude of your original number is now represented as \$v\cdot 2^p\$. But rounding hasn't yet occurred.
To round the value so that it fits within the IEEE 32-bit format, do the following step:
- if \$\left(v-\lfloor v\rfloor\right)\ge \frac{1}{2}\$, set \$v=\lfloor v\rfloor + 1\$ else set \$v=\lfloor v\rfloor\$.
You now have the sign field represented as \$\left(s\right)\$, the mantissa field represented by \$\left(v-2^m\right)\$ (hidden bit notation), and the exponent represented as \$\left(m+p+127\right)\$.
At this point, there is a final step about finding out if the exponent is representable or instead out of range. If \$0\lt \left(m+p+127\right)\lt 255\$ (for single precision), then you are fine. But if that isn't true, then in the case where \$\left(m+p+127\right)\le 0\$ you may be able to consider adapting it to a denormal format where you can preserve some, but not all, of the higher order mantissa precision bits. (A denormal sets the exponent field arbitrarily to zero.) In the other case where \$\left(m+p+127\right)\ge 255\$, you cannot represent the number in the format and you need to select an error format code, instead. These special values all set the exponent field to 255 and encode special, added meaning inside the mantissa field.
One thing that many fail to understand is the concept of the hidden bit notation. It's not complicated, but it takes a moment to consider.
Since the mantissa is normalized before packing, it's always the case that the upper-most bit is a 1 (unless the value was 0, of course.) So it's a waste of space to include it. As a result, the upper-most bit is removed (hidden) and only the remaining bits are packed into the mantissa. (It is also restored when unpacking the floating point format, too.) You can see the fact that I hide it in the above discussion where I wrote \$\left(v-2^m\right)\$: the \$-2^m\$ term is where I'm removing the hidden/upper-most bit of the mantissa.
In the case of denormals, the hidden bit isn't hidden but is instead included into the mantissa field since the exponent (excess 127 format) is always zero in this case and it isn't otherwise possible to "restore" a hidden bit since there is no information about where to put it in the case of a denormal.
-
\$\begingroup\$ So well explained! I have a trivial question, I understood the logic behind every step, except I can't understand why exponent represented as $$(m+p+127)$$ works. I understand 127 is for excess-127, and for my example, p is -23 and m is 23 so it gives the right answer but I can't get the logic. \$\endgroup\$– momoCommented Jan 13, 2018 at 2:58
-
\$\begingroup\$ @momo The reason is simple once you get it. Think about the number 1. You have to "normalize it" so that it is between 8388608 and 16777215. That is \$2^{23}\$ larger than 1. So \$p\$ is -23 at this time. Adding \$m\$ makes \$m+p=0\$ in this case, which is what you want for the exponent (before adding the excess 127 to it.) You could say it is an artifact of the normalization and the field size for the single precision mantissa. Just walk through a few examples manually and I think you will figure it out better. \$\endgroup\$– jonkCommented Jan 13, 2018 at 3:12
-
\$\begingroup\$ @momo Another way of seeing it is to realize that you don't pack 1 at the bottom of the mantissa, but instead pack the 1 at the uppermost bit (and more.) If you did just store the 1 as 0000...00001 in the mantissa, then I think your intuition would be right. But we store it as 10000.....00000, instead. So you have to account for the number of bits here that it is normalized by. I'm trying to find the right words. The picture is clear to me, but words are lacking. Which is why I say you should just do a few cases and see. \$\endgroup\$– jonkCommented Jan 13, 2018 at 3:17
-
\$\begingroup\$ thank you very much! I'll come back read your comments again after I've practised a bit. \$\endgroup\$– momoCommented Jan 13, 2018 at 9:24
There is an age-old adage:
If you give a person a fish, you feed that person for one day.
If you teach a person to fish, you feed that person for a life-time.
I will tell you how to find the IEEE single-precision floating point number for some decimal numbers.
Let us begin with scientific notation.
Usually, scientists prefer seeing option 1 over option 2, where options 1 and 2 are both shown below:
- \$5.6 * 10^{7}\$
- \$0.0056 * 10^{4}\$
If you write numbers in scientific notation, you are not supposed to write \$0.0056 * 10^{4}\$. You are supposed to slide all of the numbers to the left or to the right until there is exactly one non-zero digit to the left of the decimal point.
The decimal expansions of both mathematical expressions are the same, but \$0.0056\$ has too many zeros to the left of the decimal-point.
You can write \$0.5\$ as \$5.0 * 10^{-1}\$.
Note that a normalized IEEE float can be thought of as:
\$(\mathtt{SIGN\_BIT}) * (\mathtt{FRACTION}) * 2^{(\mathtt{EXPONENT})} \$
So, we could have:
\$0.5 = \underbrace{(+1)}_{\mathtt{SIGN\_BIT}} * \underbrace{(5.0)}_{\mathtt{FRACTION}} * \underbrace{(10^{-1})}_{\mathtt{EXPONENT}}\$
- The \$\mathtt{SIGN\_BIT}\$ is either \$(+1)\$ or \$(-1)\$.
- The \$\mathtt{BASE}\$ will be stored inside of \$23\$ bits.
- The \$\mathtt{POWER}\$, also known as the \$\mathtt{EXPONENT}\$, fits inside of \$8\$ bits.
One single bit is like one single single square on a sheet of graph paper.
Note that:
\$0.5 = \dfrac{1}{2}\$
\$\dfrac{1}{2}\$ becomes $2^{-1}$
\$2^{-1}\$ becomes \$1*2^{-1}\$
Notice that there is a non-zero digit to the left of the decimal point in 0.5 * 10^{0}
. slide the 5
in 0.5* 10^{0}
to the left to get \$5.0 * 10^{-1}\$
The mathematical expression \$1*2^{-1}\$ looks almost like scientific-notation, except that we use a two instead of a ten.
To summarize:
\$0.5 = \begin{pmatrix}\dfrac{1}{2}\end{pmatrix} = 2^{-1}\$
Now, we can do that in base 2 instead of base 10.
\$(0.1 * 10^{-1})_{2}\$ has a zero on the left of the binary-point.
\$(1.0 * 10^{-2})_{2}\$ has a $1$ to the left of the binary-point.
The people who wrote the IEEE standards assumed that \$\mathtt{BASE}\$ would always start with a \$1\$. Those people preferred option 1 over option 2 where options 1 and 2 are shown below.
- \$one \quad dot \quad something \quad something\$
- \$zero \quad dot \quad something \quad something\$
As such you should slide things around until you have (one - point - something) times \$2\$ raised to some power.
We never bother to record the \$1\$ to the left of the binary-point.
We are not allowed to have zero-dot-something.
If the number is always one-dot-something, then why bother recording the one?
For recording \$0.5\$ we record \$(0.0 * 10^{-2})_{2}\$ instead of recording \$(0.0 * 10^{-2})_{2}\$.
When converting from the numbers people write on paper with pencils into IEEE format, delete the leftmost \$1\$ from the base.
Thus, \$(1.100101)_{2}*(10)_{2}^{(1010)_{2}}\$ is stored as \$(0.100101)_{2}*(10)_{2}^{(1010)_{2}}\$ because we delete the leftmost \$1\$ in the base of a normalized floating point number.
Note that the \$\mathtt{BASE}\$ is never allowed to be equal to the number zero.
So we want something like the following for 0.5
:
\$(\mathtt{SIGN\_BIT}) * (\mathtt{BASE}) * (\mathtt{POWER}) \$
\$\underbrace{(+1)}_{ \mathtt{SIGN\_BIT}} * \underbrace{(1)}_{\mathtt{BASE}} * \underbrace{(2^{-1})}_{\mathtt{POWER} }\$
This answer could use some heavy revision.
Feel free to edit what I have written.