[cairo] Banker's rounding problems and Nautilus
Bill Spitzak
spitzak at d2.com
Fri Dec 1 19:39:41 PST 2006
The following code appears to do floor(x+.5) quickly. However two
additions are necessary, as it is impossible to get the extra correction
of .25 and the large factor into the same constant becuase it requires
higher precision than the double can hold. Somebody needs to test if
this is still faster, and also that the optimizer does not merge the two
constants. Some technique to produce an 80-bit constant would also work.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#if __BIG_ENDIAN__
#define iman_ 1
#else
#define iman_ 0
#endif
typedef union {
double v;
long word[2];
long long big;
} Double_Long;
// Does floor(x) but quickly. Works for -1073741824 to 1073748823.9977785
inline long fast_floor(double val) {
Double_Long v; v.v = (val-.25) + (68719476736.0*32768.0*1.5);
return v.word[iman_] >> 1;
}
// Does floor(x+.5) but quickly. Works for -1073741824.5 to
1073741823.49987785
inline long fast_rfloor(double val) {
Double_Long v; v.v = (val+.25) + (68719476736.0*32768.0*1.5);
return v.word[iman_] >> 1;
}
int main(int argc, char** argv) {
int i, j;
double f;
if (argc < 2) {
fprintf(stderr, "Return fast_rfloor(x) for each argument\n");
return 1;
}
for (i = 1; i < argc; i++) {
f = strtod(argv[i],0);
j = fast_rfloor(f);
printf("fast_rfloor(%g) = %d\n", f,j);
}
return 0;
}
More information about the cairo
mailing list