# How are bitwise operators used in normalisation of floating-point numbers?

After having spent a significant amount of time googling this topic, I am still struggling to confidently answer the following question:

Identify the process using logical operators to normalise a floating-point number.


My first assumption was, we use the binary shift to remove the leading 0's (for positive numbers) or 1's (for negative numbers) and then use XOR to increase the exponent by the required amount.

I do not understand, however, what happens to the binary point.

Let's say we have the number 1.75 represented as 000001.11 in 8-bits. If I shift it to the right by one place, I lose the 1 at the end. If I shift it to the left by 4 places, how does the computer know to move the binary point between the first two bits from the left? I am lost. How do bitwise operations work in this case?

Thank you in advance for your time and help.

• Where does the prompt quoted come from? There should be a context with details about normalised floating-point number. – greybeard Sep 23 '20 at 6:49
• Very strange question. Was that written by a native English speaker? – gnasher729 Oct 22 '20 at 12:54

It's helpful to think of the number in the following representation( I choose 3.75 as an example): $$2^0 * 11.11_2 = 3.15$$ Now $$2^0 = 1$$ so we can just write it in front of the number. Now we want to normalize $$3.75$$ meaning we need to transform it to $$2^e * 1.m$$ where $$e$$ and $$m$$ are some bitstrings. Notice that we can shift a binary number to the left by dividing it by to e.g. $$4 = 100_2 = 2* 010_2 = 2*2* 001_2$$. I hope you can see how dividing/multiplying by 2 corresponds to shifting (in base 2!). Lets shift 3.75 in such a way that a 1 is in front of the comma: $$2^0 * 11.11_2 0 = 2^1* 1.111_2$$; as you can see we shifted 3.75 and thereby pulled a $$2$$ out of it and increased the exponent to account for the $$2$$. The value of the number is still 3.75 it's just written down as $$2* 1.875$$. This is the normalized form. Now the exponent $$e$$ and the places behind the comma are stored in a floating point number. Why don't we need the $$1$$ in front of the comma? Cause the normalized form guarantees that there is a 1 so it's redundant to store it.

• for details on how the number is stored and how negative numbers and e.g. zero are represented in e.g. the IEE 754 float32 format check out en.wikipedia.org/wiki/IEEE_754 – plshelp Sep 22 '20 at 2:40
• Thank you! It's not quite what I meant though. I do understand how normalisation is done and why it is done. I just don't know how to account for the fact that in the example I've given above, the first 1 on the right would disappear if I shifted the bits to the right by one place in order to normalise the number. A shift to the right puts the 1's outside the range of 8-bits, no? And then, how do I get rid of leading 0's, whilst simultaneously keeping the binary point in front of 1's. – DeadManProp Sep 22 '20 at 19:01

Normalising floating-point numbers will most likely be done in hardware. It will use bit operations, but not visible to the programmer using it. And normalising will be done in very close conjunction with rounding.

Floating-point numbers usually consist of a sign bit, an exponent field, and a mantissa field. Since floating-point numbers are supposed to be normalised, which means the highest bit of the mantissa is supposed to be 1, this is often not stored. In addition, you will have tiny numbers that are denormalised (they are so small that if they were normalised, you wouldn't be able to store the exponent), and you have special values like infinities and not-a-numbers.

In floating-point arithmetic, usually the first step is detecting special values and handling them. For example, +inf / NaN = NaN, +inf * any positive number = +inf, etc. etc. There are lots of special cases, but you just follow the definition what the results should be. For multiplication and division, zeroes may also be handled as a special case.

For multiplication and division, you normalise denormalised numbers. You count the leading zero bits in the mantissa, then shift the mantissa to the left to have the leading bit set, and subtract the shift count from the exponent. You add or subtract the exponents and perform the multiplication division, giving a larger mantissa than needed. Depending on the inputs, the highest bit of the result mantissa may be cleared. In that case you shift the result mantissa to the left and decrease the exponent. Now you perform rounding based on the extra mantissa bits you have. Rounding can lead to overflow, in which case the exponent is increased. Finally you check the exponent: If it is too large, the result becomes infinity, If it is too small, the result will be a denormalised number, possibly zero.

For addition and subtraction, you need to have identical exponents. So you shift the mantissa with the smaller exponent to the right. Then you perform the addition or subtraction. You may have a huge number of leading zero bits, so you shift the mantissa to the left by possibly many bit positions and change the exponent. You don't change it to something lower than the exponent for denormalised numbers. And then you perform rounding, again checking for overflows.

So the bit operations that you perform are: Extracting sign bit, exponent and mantissa, processing sign bits. Normalising denormalised numbers by counting leading bits, shifting, and adjusting exponents. Normalising results again by counting leading bits etc. Rounding is done using logical operations.