CrystalSpace

Public API Reference

Main Page | Modules | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members | Related Pages

csqint.h File Reference

Quick floating point to integer conversions. More...

Go to the source code of this file.

Functions

long csQint (double inval)
 Truncate the fractional part of a floating-point value and convert to integer.
long csQround (double inval)
 Round a floating-point value and convert to integer.
long csQint8 (float inval)
 Convert a floating-point number to 24.8 fixed-point value.
long csQint16 (float inval)
 Convert a floating-point number to 16.16 fixed-point value.
long csQint24 (float inval)
 Convert a floating-point number to 8.24 fixed-point value.


Detailed Description

Quick floating point to integer conversions.

There is a general trick that can be used on all FPUs that uses IEEE double-precision floating-point number format (theoretically it should cover all CPUs that have a "double" data type of 64 bits; it is applicable for other types as well, but you have to figure out yourself how - it's easy if you understand everything that is written below) to quickly convert numbers from floating-point format to integer and fixed-point formats. Let's take the "double" type format (on x86, e.g. little-endian):

 bit 0        8        16       24       32       40       48       56   sign
    +--------+--------+--------+--------+--------+--------+--------+-------|+
    |mmmmmmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm|mmmmeeee|eeeeeees|
    +|-------+--------+--------+--------+--------+--------+---||---+------|-+
     \------------------------- mantissa ---------------------/\-exponent-/

In the following we'll picture numbers as (s)m^e, e.g. (0)2^1 is the number '2', (1)2^5 means number -32. This means that the number "127" will be represented as

    (0)2^7 + 2^6 + 2^5 + ... + 2^0, or

    00000000.00000000.00000000.00000000.00000000.00000111.1111|1110.00000000

(well, in general exponent is stored + 0x3ff but we will not take this into account... consider we'll always subtract 0x3ff from exponent).

So observe several things. First, the exponent is 111b (e.g. 7) - the most significant power of two in above series. Next, observe that the mantissa contains just 7 '1' bits while 255 contains 8 '1' bits. Well, the topmost bit is always considered '1' except for the case of 'zero'.

Now what if we add, say, 2^20 to the above number (i.e. 255+2^20)? The most significant power of two is 20 then, so all bits with lower significance will just shift left by 20 bits:

    (0)2^20 + 2^7 + 2^6 + 2^5 + 2^4 + 2^3 + 2^2 + 2^1 + 2^0, or

    00000000.00000000.00000000.00000000.11111111.00000000.0000|0010.10000000

So what we see? Our beloved 255 has moved to the left and we can just pick it by taking the fifth byte of the floating-point number. So if we need to convert any number from 0 to 2^20-1 from floaring-point format to integer format, we can just add 2^20 to him and pick the respective bytes from the "double" variable. If we would need a fixed-point value, we also can take the bytes prior to integer value (they will contain the fractional part). So if we would need a 16.16 format, we can add 2^20 and take bits 16-31 (fractional part) and 23-48 (integer part).

Now what we will do with negative numbers? The problem is that when you 'shift' left an negative number by adding, say, 2^20, the most significant bits are filled with '1' rather than with '0' because your number is subtracted from 2^20 rather than added. Thus 2^20-1 will look like this:

    00000000.00000000.00000000.00000000.01111111.11111111.1111|1100.10000000

Thus if we'll get the fifth byte as before, we'll get '-2' rather than '-1'. So we would have to check whenever we should shift the result or not depending on his sign. If rounding number (instead of truncating the fractional part) is acceptable, we can do another trick: add 2^20 + 2^8, and after taking the required subpart subtract 2^8 back.

Measurements show that this trick is even faster (at least on P5 and above) than FISTP command (even if we use the (correct) presumption that FPU is in rounding mode by default, e.g. no need to toggle FPU control word). csQround executes 2 clocks on Celeron while FISTP executes 13 clocks, i.e. about 6 times slower.

All said above is true for all CPU types that uses standard IEEE format for "double" type, with the respective corrections for endianess.

Definition in file csqint.h.


Generated for Crystal Space by doxygen 1.3.9.1