[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