Google Search

Thursday, March 26, 2009

Floating Point

A friend asked me today why a cast from double to int in C# would take a whole microsecond.
To answer that, we have to understand how cast between those two primitive types work, and how each of them is represented in memory.

So, how an integer is represented in memory? Quite straight forwards: simple run of bits (8, 16, 32 or 64, depending on the actual type - byte, short, int and long respectively)

The single and double data types are more complex. These are floating point types, and as such, they represent a number which decimal point isn't in a fixed position, but may change according to the represented number.
This leads to a situation where we can represent either really small and very accurate numbers, or very large and inaccurate numbers.

How is this done? By separating the given memory to 3: one bit for sign, 11 bits for exponent, and the rest 52 bits for the mantissa (the significant value, representing a fraction or an integer depending on the interpretation of the exponent).

This structure also allows to define values that are not numbers, such as NaNs (Not a Number, which is returned when you try to divide a double by a zero double), Infinity (positive and negative), and denormal numbers.

As I mentioned before, the integer data type simply store bits, straight forwards. So, simply renaming the type won't work. A computation need to be performed to resolve the represented value from the floating point number, then round the result to the nearest whole number. In addition, several tests need to be performed to handle NaNs, denormal numbers and infinities correctly. All of those operations take quite some time, so no wonder this simple, so common cast, takes a whole microsecond.

So if you have a tidious, tight loop that performs thousands of double-to-int casts, try to avoid casting. It might help improve performance.

No comments:

Post a Comment