RSS | technovelty home | page of ian | ianw@ieee.org
You probably already know that a floating point number is
represented in binary as sign * significand *
radixexponent. Thus you can represent the
number 20.23 with radix 10 (i.e. base 10) as 1 * .2023 *
102 or as 1 * .02023 *
103.
Since one number can be represented in different ways, we define we
defined the normalised version as the one that satisfies
1/radix <= significand < 1. You can read that as saying
"the leftmost number in the significand should not be zero".
So when we convert into binary (base 2) rather than base 10, we are saying that the "leftmost number should not be zero", hence, it can only be one. In fact, the IEEE standard "hides" the 1 because it is implied by a normalised number, giving you an extra bit for more precision in the significand.
So to normalise a floating point number you have to shift the signifcand left a number of times, and check if the first digit is a one. This is something that the hardware can probably do very fast, since it has to do it a lot. Combine this with an architecture like IA64 which has a 64 bit significand, and you've just found a way to do a really cool implementation of "find the first bit that is not zero in a 64 bit value", a common operation when working with bitfields (it was really David Mosberger who originally came up with that idea in the kernel).
#define ia64_getf_exp(x) \
({ \
long ia64_intri_res; \
\
asm ("getf.exp %0=%1" : "=r"(ia64_intri_res) : "f"(x)); \
\
ia64_intri_res; \
})
int main(void)
{
long double d = 0x1UL;
long exp;
exp = ia64_getf_exp(d);
printf("The first non-zero bit is bit %d\n", exp - 65535);
}
Note the processor is using an 82 bit floating point implementation, with a 17 bit exponent component. Thus we use a 16 bit (0xFFFF, or 65535) bias so we can represent positive and negative numbers (i.e, zero is represented by 65535, 1 by 65536 and -1 by 65534) without an explicit sign bit.
IA64 uses the floating point registers in other interesting ways
too. For example, the clear_page() implementation in the
kernel spills zero'd floating point registers into memory because that
provides you with the maximum memory bandwidth. The libc
bzero() implementation does a similar thing.
posted at: Mon, 11 Apr 2005 13:10 | in /code/linux | permalink | add comment (0 others)

This work is licensed under a Creative Commons Attribution-ShareAlike 2.5 License.