core/vil/vil_round.h
Go to the documentation of this file.
00001 // This is core/vil/vil_round.h
00002 #ifndef vil_round_h_
00003 #define vil_round_h_
00004 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00005 #pragma interface
00006 #endif
00007 //:
00008 // \file
00009 // \brief Namespace with standard rounding functions.
00010 //
00011 //  These are just copies of the vnl_math rounding functions.
00012 
00013 #include <vxl_config.h>
00014 #include <vil/vil_config.h> // for VIL_CONFIG_ENABLE_SSE2_ROUNDING
00015 #ifdef VNL_CHECK_FPU_ROUNDING_MODE
00016 # include <vcl_cassert.h>
00017 #endif
00018 
00019 // Figure out when the fast implementation can be used
00020 #if VIL_CONFIG_ENABLE_SSE2_ROUNDING
00021 # if !VXL_HAS_EMMINTRIN_H
00022 #   error "Required file emmintrin.h for SSE2 not found"
00023 # else
00024 #   include <emmintrin.h> // sse 2 intrinsics
00025 # endif
00026 #endif
00027 
00028 // Turn on fast impl when using GCC on Intel-based machines with the following exception:
00029 //   PPC with Mac OS X
00030 #if defined(__GNUC__) && (!defined(__APPLE__)  || !defined(__ppc__) )
00031 # define GCC_USE_FAST_IMPL 1
00032 #else
00033 # define GCC_USE_FAST_IMPL 0
00034 #endif
00035 // Turn on fast impl when using msvc on 32 bits windows
00036 #if defined(VCL_VC) && !defined(_WIN64)
00037 # define VC_USE_FAST_IMPL 1
00038 #else
00039 # define VC_USE_FAST_IMPL 0
00040 #endif
00041 
00042 
00043 
00044 
00045 // vil_round_rnd_halfinttoeven  -- round towards nearest integer
00046 //         halfway cases are rounded towards the nearest even integer, e.g.
00047 //         vil_round_rnd_halfinttoeven( 1.5) ==  2
00048 //         vil_round_rnd_halfinttoeven(-1.5) == -2
00049 //         vil_round_rnd_halfinttoeven( 2.5) ==  2
00050 //         vil_round_rnd_halfinttoeven( 3.5) ==  4
00051 //
00052 // We assume that the rounding mode is not changed from the default
00053 // one (or at least that it is always restored to the default one).
00054 
00055 #if VIL_CONFIG_ENABLE_SSE2_ROUNDING // Fast sse2 implementation
00056 
00057 inline int vil_round_rnd_halfinttoeven(float  x)
00058 {
00059 # if defined(VIL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__)
00060   assert(fegetround()==FE_TONEAREST);
00061 # endif
00062   return _mm_cvtss_si32(_mm_set_ss(x));
00063 }
00064 inline int vil_round_rnd_halfinttoeven(double  x)
00065 {
00066 # if defined(VIL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__)
00067   assert(fegetround()==FE_TONEAREST);
00068 # endif
00069   return _mm_cvtsd_si32(_mm_set_sd(x));
00070 }
00071 
00072 #elif GCC_USE_FAST_IMPL // Fast gcc asm implementation
00073 
00074 inline int vil_round_rnd_halfinttoeven(float  x)
00075 {
00076 # ifdef VIL_CHECK_FPU_ROUNDING_MODE
00077   assert(fegetround()==FE_TONEAREST);
00078 # endif
00079   int r;
00080   __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st");
00081   return r;
00082 }
00083 inline int vil_round_rnd_halfinttoeven(double  x)
00084 {
00085 # ifdef VIL_CHECK_FPU_ROUNDING_MODE
00086   assert(fegetround()==FE_TONEAREST);
00087 # endif
00088   int r;
00089   __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st");
00090   return r;
00091 }
00092 
00093 #elif VC_USE_FAST_IMPL // Fast msvc asm implementation
00094 
00095 inline int vil_round_rnd_halfinttoeven(float  x)
00096 {
00097   int r;
00098   __asm {
00099     fld x
00100     fistp r
00101   }
00102   return r;
00103 }
00104 inline int vil_round_rnd_halfinttoeven(double  x)
00105 {
00106   int r;
00107   __asm {
00108     fld x
00109     fistp r
00110   }
00111   return r;
00112 }
00113 
00114 #else // Vanilla implementation
00115 
00116 inline int vil_round_rnd_halfinttoeven(float  x)
00117 {
00118   if (x>=0.f)
00119   {
00120      x+=0.5f;
00121      const int r = static_cast<int>(x);
00122      if ( x != static_cast<float>(r) ) return r;
00123      return 2*(r/2);
00124   }
00125   else
00126   {
00127      x-=0.5f;
00128      const int r = static_cast<int>(x);
00129      if ( x != static_cast<float>(r) ) return r;
00130      return 2*(r/2);
00131   }
00132 }
00133 inline int vil_round_rnd_halfinttoeven(double x)
00134 {
00135   if (x>=0.)
00136   {
00137      x+=0.5;
00138      const int r = static_cast<int>(x);
00139      if ( x != static_cast<double>(r) ) return r;
00140      return 2*(r/2);
00141   }
00142   else
00143   {
00144      x-=0.5;
00145      const int r = static_cast<int>(x);
00146      if ( x != static_cast<double>(r) ) return r;
00147      return 2*(r/2);
00148   }
00149 }
00150 
00151 #endif
00152 
00153 
00154 
00155 // vil_round_rnd_halfintup  -- round towards nearest integer
00156 //         halfway cases are rounded upward, e.g.
00157 //         vil_round_rnd_halfintup( 1.5) ==  2
00158 //         vil_round_rnd_halfintup(-1.5) == -1
00159 //         vil_round_rnd_halfintup( 2.5) ==  3
00160 //
00161 // Be careful: argument absolute value must be less than INT_MAX/2
00162 // for vil_round_rnd_halfintup to be guaranteed to work.
00163 // We also assume that the rounding mode is not changed from the default
00164 // one (or at least that it is always restored to the default one).
00165 
00166 #if VIL_CONFIG_ENABLE_SSE2_ROUNDING || GCC_USE_FAST_IMPL || VC_USE_FAST_IMPL
00167 
00168 inline int vil_round_rnd_halfintup(float  x) { return vil_round_rnd_halfinttoeven(2*x+0.5f)>>1; }
00169 inline int vil_round_rnd_halfintup(double  x) { return vil_round_rnd_halfinttoeven(2*x+0.5)>>1; }
00170 
00171 #else // Vanilla implementation
00172 
00173 inline int vil_round_rnd_halfintup(float  x)
00174 {
00175   x+=0.5f;
00176   return static_cast<int>(x>=0.f?x:(x==static_cast<int>(x)?x:x-1.f));
00177 }
00178 inline int vil_round_rnd_halfintup(double x)
00179 {
00180   x+=0.5;
00181   return static_cast<int>(x>=0.?x:(x==static_cast<int>(x)?x:x-1.));
00182 }
00183 
00184 #endif
00185 
00186 
00187 
00188 // vil_round_rnd  -- round towards nearest integer
00189 //         halfway cases such as 0.5 may be rounded either up or down
00190 //         so as to maximize the efficiency, e.g.
00191 //         vil_round_rnd_halfinttoeven( 1.5) ==  1 or  2
00192 //         vil_round_rnd_halfinttoeven(-1.5) == -2 or -1
00193 //         vil_round_rnd_halfinttoeven( 2.5) ==  2 or  3
00194 //         vil_round_rnd_halfinttoeven( 3.5) ==  3 or  4
00195 //
00196 // We assume that the rounding mode is not changed from the default
00197 // one (or at least that it is always restored to the default one).
00198 
00199 #if VIL_CONFIG_ENABLE_SSE2_ROUNDING || GCC_USE_FAST_IMPL || VC_USE_FAST_IMPL
00200 
00201 inline int vil_round_rnd(float  x) { return vil_round_rnd_halfinttoeven(x); }
00202 inline int vil_round_rnd(double  x) { return vil_round_rnd_halfinttoeven(x); }
00203 
00204 #else // Vanilla implementation
00205 
00206 inline int vil_round_rnd(float  x) { return x>=0.f?static_cast<int>(x+.5f):static_cast<int>(x-.5f); }
00207 inline int vil_round_rnd(double x) { return x>=0.0?static_cast<int>(x+0.5):static_cast<int>(x-0.5); }
00208 
00209 
00210 #endif
00211 
00212 
00213 
00214 // vil_round_floor -- round towards minus infinity
00215 //
00216 // Be careful: argument absolute value must be less than INT_MAX/2
00217 // for vil_round_floor to be guaranteed to work.
00218 // We also assume that the rounding mode is not changed from the default
00219 // one (or at least that it is always restored to the default one).
00220 
00221 #if VIL_CONFIG_ENABLE_SSE2_ROUNDING // Fast sse2 implementation
00222 
00223 inline int vil_round_floor(float  x)
00224 {
00225 # if defined(VIL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__)
00226   assert(fegetround()==FE_TONEAREST);
00227 # endif
00228    return _mm_cvtss_si32(_mm_set_ss(2*x-.5f))>>1;
00229 }
00230 inline int vil_round_floor(double  x)
00231 {
00232 # if defined(VIL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__)
00233   assert(fegetround()==FE_TONEAREST);
00234 # endif
00235    return _mm_cvtsd_si32(_mm_set_sd(2*x-.5))>>1;
00236 }
00237 
00238 #elif GCC_USE_FAST_IMPL // Fast gcc asm implementation
00239 
00240 inline int vil_round_floor(float  x)
00241 {
00242 # ifdef VIL_CHECK_FPU_ROUNDING_MODE
00243   assert(fegetround()==FE_TONEAREST);
00244 # endif
00245   int r;
00246   x = 2*x-.5f;
00247   __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st");
00248   return r>>1;
00249 }
00250 inline int vil_round_floor(double  x)
00251 {
00252 # ifdef VIL_CHECK_FPU_ROUNDING_MODE
00253   assert(fegetround()==FE_TONEAREST);
00254 # endif
00255   int r;
00256   x = 2*x-.5;
00257   __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st");
00258   return r>>1;
00259 }
00260 
00261 #elif VC_USE_FAST_IMPL // Fast msvc asm implementation
00262 
00263 inline int vil_round_floor(float  x)
00264 {
00265   int r;
00266   x = 2*x-.5f;
00267   __asm {
00268     fld x
00269     fistp r
00270   }
00271   return r>>1;
00272 }
00273 inline int vil_round_floor(double  x)
00274 {
00275   int r;
00276   x = 2*x-.5;
00277   __asm {
00278     fld x
00279     fistp r
00280   }
00281   return r>>1;
00282 }
00283 
00284 #else // Vanilla implementation
00285 
00286 inline int vil_round_floor(float  x)
00287 {
00288   return static_cast<int>(x>=0.f?x:(x==static_cast<int>(x)?x:x-1.f));
00289 }
00290 inline int vil_round_floor(double x)
00291 {
00292   return static_cast<int>(x>=0.0?x:(x==static_cast<int>(x)?x:x-1.0));
00293 }
00294 
00295 #endif
00296 
00297 
00298 
00299 // vil_round_ceil -- round towards plus infinity
00300 //
00301 // Be careful: argument absolute value must be less than INT_MAX/2
00302 // for vil_round_ceil to be guaranteed to work.
00303 // We also assume that the rounding mode is not changed from the default
00304 // one (or at least that it is always restored to the default one).
00305 
00306 #if VIL_CONFIG_ENABLE_SSE2_ROUNDING // Fast sse2 implementation
00307 
00308 inline int vil_round_ceil(float  x)
00309 {
00310 # if defined(VIL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__)
00311   assert(fegetround()==FE_TONEAREST);
00312 # endif
00313    return -(_mm_cvtss_si32(_mm_set_ss(-.5f-2*x))>>1);
00314 }
00315 inline int vil_round_ceil(double  x)
00316 {
00317 # if defined(VIL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__)
00318   assert(fegetround()==FE_TONEAREST);
00319 # endif
00320    return -(_mm_cvtsd_si32(_mm_set_sd(-.5-2*x))>>1);
00321 }
00322 
00323 #elif GCC_USE_FAST_IMPL // Fast gcc asm implementation
00324 
00325 inline int vil_round_ceil(float  x)
00326 {
00327 # ifdef VIL_CHECK_FPU_ROUNDING_MODE
00328   assert(fegetround()==FE_TONEAREST);
00329 # endif
00330   int r;
00331   x = -.5f-2*x;
00332   __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st");
00333   return -(r>>1);
00334 }
00335 inline int vil_round_ceil(double  x)
00336 {
00337 # ifdef VIL_CHECK_FPU_ROUNDING_MODE
00338   assert(fegetround()==FE_TONEAREST);
00339 # endif
00340   int r;
00341   x = -.5-2*x;
00342   __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st");
00343   return -(r>>1);
00344 }
00345 
00346 #elif VC_USE_FAST_IMPL // Fast msvc asm implementation
00347 
00348 inline int vil_round_ceil(float  x)
00349 {
00350   int r;
00351   x = -.5f-2*x;
00352   __asm {
00353     fld x
00354     fistp r
00355   }
00356   return -(r>>1);
00357 }
00358 inline int vil_round_ceil(double  x)
00359 {
00360   int r;
00361   x = -.5-2*x;
00362   __asm {
00363     fld x
00364     fistp r
00365   }
00366   return -(r>>1);
00367 }
00368 
00369 #else // Vanilla implementation
00370 
00371 inline int vil_round_ceil(float  x)
00372 {
00373   return static_cast<int>(x<0.f?x:(x==static_cast<int>(x)?x:x+1.f));
00374 }
00375 inline int vil_round_ceil(double x)
00376 {
00377   return static_cast<int>(x<0.0?x:(x==static_cast<int>(x)?x:x+1.0));
00378 }
00379 
00380 #endif
00381 
00382 
00383 #endif // vil_round_h_