How we got exponent as $2^{127-64}$?

Information: Consider a 16-bit register of the following format is used to store a floating point number. Mantissa (M) is denoted as normalized signed magnitude fraction, Exponent (E) is expressed in excess-64 form. Base of the system is 2.

If we calculate then, we get, exponent is allotted 7 bits and Mantissa is allotted 8 bits.

Therefore, largest number that can be represented using this information is as follows:

| 0 | 1 1 1 1 1 1 1 | 1 1 1 1 1 1 1 1 |


i.e. filling every bit with 1 and as we are looking for largest number we are having sign of the number as 0.

What is the value of the largest number that can be represented in base 10?

We will use following formula: $$\(-1)^S * 1.M * 2^{E-B}\$$ i.e. implicit normalization with biasing.

I don't understand the exponent part of the number

How we got exponent as $$\2^{127-64}\$$. Why we are subtracting bias 64 from exponent 127?

Can someone explain me with proper derivation/explanation that how we arrived at $$\2^{127-64}\$$? Please explain it as you are explaining to naive person.

I am missing something very obvious!

Waiting for explanation!

• I don't know why my latex code is not reflecting proper format? Apr 24, 2020 at 2:37
• This is different than other stack exchanges. You need \ $for inline or$ \$ for centered. Apr 24, 2020 at 2:40
• @DKNguyen I have updated. Thank you! Apr 24, 2020 at 2:53
• I'll discuss the details why, later on. I first want to allow DK to have a shot at it. (It is not quite a circuitry question.)
– jonk
Apr 24, 2020 at 3:25
• @jonk sure I'll wait. Apr 24, 2020 at 3:27

The exponent is biased so that the format can better represent fractional numbers between 0 and 1. It's a way to extend the lower extent in range of precision that the format can handle. It turns out that values from 0 to 1 are quite important in most floating point calculation, more important than representing bigger magnitudes, so sacrificing half the upper range is a reasonable trade-off.

But there's another, more important reason for using bias (as opposed to 2’s complement) that I'll get to later, a reason that goes back to the very beginnings of floating point.

Anyway, in this format you basically have these key values and ranges:

 - zero                                 (sign, exp 0x00-64, mant 0.0x00)
- denormals                            (sign, exp 0x00-64, mant 0.0x01 ~ 0.0xff)
- smallest normalized less than one    (sign, exp 0x01-64, mant 1.0x00)
- largest nomalized less than one      (sign, exp 0x3e-64, mant 1.0xff)
- one                                  (sign, exp 0x3f-64, mant 1.0x00)
- smallest normalized greater than one (sign, exp 0x40-64, mant 1.0x00)
- largest normalized greater than one  (sign, exp 0x7f-64, mant 1.0xff)


Some fine points:

• For all the cases except zero and denormal, the mantissa value is 1.mant, which gives a range of 1 to just 1 mantissa LSB less than 2 (that is, 1 + 0/256 to 1 + 255/256).
• Because of the way sign is handled, there are two representations of zero: +0 and -0.

This example format is something like what IEEE754 does. IEEE754 also reserves special values for -infinity, +infinity, and not-a-number (NaN). Play around with it here: https://www.h-schmidt.net/FloatConverter/IEEE754.html

And now, the buried lede: Why use bias at all? Because it avoids needing to use 2's complement in the exponent, which would make simple greater- and less-than comparisons between float values harder.

With bias, you can do a magnitude compare with just a single integer subtract of the mantissa and exponent fields (sign bit is masked off and handled separately.) That’s not possible if 2’s were used for the exponent, as negative exponents would look like large integer values to an integer compare, giving a wrong result.

In other words, a biased exponent yields an always-increasing integer value from zero to positive infinity. (Try it in that app I linked.)

The side-effect of using bias is that it complicates float-to-fixed and fixed-to-float, but this is usually a rare operation that in any event is efficiently dealt with by the FPU.

And I mentioned a history of bias. The IBM 709 used biased exponents, way back in 1957, as did its predecessor, the 704, in 1954.

• Pretty close. Good enough for a +1. Saves me a bunch of writing! Thanks! (Youngsters like DK don't remember stuff like this.)
– jonk
Apr 24, 2020 at 4:04
• I knew writing the WTL3164 sim would come in handy someday ;-) That, and, expanding Kahan's patterns to handle all the rounding cases too. It's been a long time since I've thought about this stuff. Apr 24, 2020 at 4:09
• Stuff gets forgotten over time. New folks have no clues about how it was and have to make stuff up that "sounds right." But those there at the time remember. Until we die. Which brings up a different reality. That those born today know nothing at all. And those of us dying take everything we know with us to the grave. In between, there is a treadmill upon which we must run, passing along what we know to those younger or else it is lost forever. Maintaining a civilization at a certain level means passing it on, fast. Improving, means even more. The alternative is decline. So it must be.
– jonk
Apr 24, 2020 at 4:15
• Yes. The loss of knowledge and culture is inevitable. There is knew knowledge, too. But it is sad to see what was known, disappearing. I fear that what we lose is more than what we gain. But I don't know. I'm working on a "mullion" for a french door system, today, that is essentially lost knowledge, now. Luckily, there are still a small few who remember. So I'm lucky there. I also have a break-front (furniture) that was built in 1880's. After all these years, and with all the humidity and temp changes, it still closes with an "air seal." That knowledge about grain and wood is now gone. Sad.
– jonk
Apr 24, 2020 at 4:30
• @Ubihatt Try this: #include <iostream> int main() { double a[5] = { -100.0, -0.25, -14.6, -225.0, -171.3 }; qsort(&a[0], 5, sizeof(double), [](const void* a, const void* b) { if ((long long int)a > * (long long int*)b) return 1; else if ((long long int)a < (long long int)b) return -1; return 0; }); std::cout << a[0] << ' ' << a[1] << ' ' << a[2] << ' ' << a[3] << ' ' << a[4] << std::endl; return 0; }And then remove the signs and try again.
– jonk
Apr 25, 2020 at 6:16

Being able to represent a number with a negative exponent is useful for representing numbers between zero and one. How else would you be able to have negative exponents if you didn't offset it by half of the full scale (half of 128 is 64)? I suppose you could represent the exponent in twos compliment, but they don't do that. Probably takes more circuitry than it is worth.

• I am computer science student and I have specific problem. I'm new to this topic & I am still in learning phase. Apr 24, 2020 at 2:53
• Hi, DK, There is a different reason for the bias/excess. Can you think of why? (I was there when it was discussed.)
– jonk
Apr 24, 2020 at 3:20