Introduction
Those of you who are after sheer running speed already know how slow the standard floor/ceiling functions can be. Here are handy alternatives.
Background
The standard floor/ceiling functions have two drawbacks:
- they are shockingly slow, and
- they return a floating-point value;
when what you want is an integer, this costs you an extra conversion
to int
, which seems extraneous.
You will find alternatives on the Web, most being built on a cast to int
. Unfortunately, this cast rounds towards zero, which gives wrong results for negative values.
Some try to fix this by subtracting 1
for negative arguments. This solution is still not compliant with the function definition, as it does not work for negative integer values.
Closer scrutiny shows that the -1
adjustment is required for all negative numbers with a nonzero fractional value. This occurs exactly when the result of the cast is larger than the initial value. This gives:
i= int(fp); if (i > fp) i--;
It involves a single comparisons and an implicit type conversion (required by the comparison).
Similarly, the ceiling function needs to be adjusted for positive fractional values.
i= int(fp); if (i < fp) i++;
Using the code
A faster and correct solution is obtained by shifting the values before casting, to make them positive. For instance, assuming all your values fit in the range of a short
,
you will use:
i= (int)(fp + 32768.) - 32768;
That costs a floating-point add, a typecast and an integer add. No branch.
The ceiling function is derived by using the property floor(-fp) = -ceiling(fp)
:
i= 32768 - (int)(32768. - fp);
Points of Interest
I benchmarked the (int)floor/ceil
functions, the comparison-based and the shifting-based expressions by running them 1000 times on an array of 1000 values in range -50..50.
Here are the times in nanoseconds per call.
Floor:
- Standard function: 24 ns
- Comparison based: 14 ns
- Shifting based: 2.6 ns
Ceiling:
- Standard function: 24 ns
- Comparison based: 14 ns
- Shifting based: 2.8 ns
This clearly shows that it is worth to use the shifting alternatives.
History
- Second version, simpler comparison-based version and ceiling handled.