vil_round.h
Go to the documentation of this file.
1 // This is core/vil/vil_round.h
2 #ifndef vil_round_h_
3 #define vil_round_h_
4 //:
5 // \file
6 // \brief Namespace with standard rounding functions.
7 //
8 // These are just copies of the vnl_math rounding functions.
9 
10 #include <vxl_config.h>
11 #include <vil/vil_config.h> // for VIL_CONFIG_ENABLE_SSE2_ROUNDING
12 #ifdef VNL_CHECK_FPU_ROUNDING_MODE
13 # include <vcl_cassert.h>
14 #endif
15 
16 // Figure out when the fast implementation can be used
17 #if VIL_CONFIG_ENABLE_SSE2_ROUNDING
18 # if !VXL_HAS_EMMINTRIN_H
19 # error "Required file emmintrin.h for SSE2 not found"
20 # else
21 # include <emmintrin.h> // sse 2 intrinsics
22 # endif
23 #endif
24 
25 // Turn on fast impl when using GCC on Intel-based machines
26 #if defined(__GNUC__) && ((defined(__i386__) || defined(__i386) || defined(__x86_64__) || defined(__x86_64)))
27 # define GCC_USE_FAST_IMPL 1
28 #else
29 # define GCC_USE_FAST_IMPL 0
30 #endif
31 // Turn on fast impl when using msvc on 32 bits windows
32 #if defined(_MSC_VER) && !defined(_WIN64)
33 # define VC_USE_FAST_IMPL 1
34 #else
35 # define VC_USE_FAST_IMPL 0
36 #endif
37 
38 
39 
40 
41 // vil_round_rnd_halfinttoeven -- round towards nearest integer
42 // halfway cases are rounded towards the nearest even integer, e.g.
43 // vil_round_rnd_halfinttoeven( 1.5) == 2
44 // vil_round_rnd_halfinttoeven(-1.5) == -2
45 // vil_round_rnd_halfinttoeven( 2.5) == 2
46 // vil_round_rnd_halfinttoeven( 3.5) == 4
47 //
48 // We assume that the rounding mode is not changed from the default
49 // one (or at least that it is always restored to the default one).
50 
51 #if VIL_CONFIG_ENABLE_SSE2_ROUNDING // Fast sse2 implementation
52 
53 inline int vil_round_rnd_halfinttoeven(float x)
54 {
55 # if defined(VIL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__)
56  assert(fegetround()==FE_TONEAREST);
57 # endif
58  return _mm_cvtss_si32(_mm_set_ss(x));
59 }
60 inline int vil_round_rnd_halfinttoeven(double x)
61 {
62 # if defined(VIL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__)
63  assert(fegetround()==FE_TONEAREST);
64 # endif
65  return _mm_cvtsd_si32(_mm_set_sd(x));
66 }
67 
68 #elif GCC_USE_FAST_IMPL // Fast gcc asm implementation
69 
70 inline int vil_round_rnd_halfinttoeven(float x)
71 {
72 # ifdef VIL_CHECK_FPU_ROUNDING_MODE
73  assert(fegetround()==FE_TONEAREST);
74 # endif
75  int r;
76  __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st");
77  return r;
78 }
79 inline int vil_round_rnd_halfinttoeven(double x)
80 {
81 # ifdef VIL_CHECK_FPU_ROUNDING_MODE
82  assert(fegetround()==FE_TONEAREST);
83 # endif
84  int r;
85  __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st");
86  return r;
87 }
88 
89 #elif VC_USE_FAST_IMPL // Fast msvc asm implementation
90 
91 inline int vil_round_rnd_halfinttoeven(float x)
92 {
93  int r;
94  __asm {
95  fld x
96  fistp r
97  }
98  return r;
99 }
100 inline int vil_round_rnd_halfinttoeven(double x)
101 {
102  int r;
103  __asm {
104  fld x
105  fistp r
106  }
107  return r;
108 }
109 
110 #else // Vanilla implementation
111 
112 inline int vil_round_rnd_halfinttoeven(float x)
113 {
114  if (x>=0.f)
115  {
116  x+=0.5f;
117  const int r = static_cast<int>(x);
118  if ( x != static_cast<float>(r) ) return r;
119  return 2*(r/2);
120  }
121  else
122  {
123  x-=0.5f;
124  const int r = static_cast<int>(x);
125  if ( x != static_cast<float>(r) ) return r;
126  return 2*(r/2);
127  }
128 }
129 inline int vil_round_rnd_halfinttoeven(double x)
130 {
131  if (x>=0.)
132  {
133  x+=0.5;
134  const int r = static_cast<int>(x);
135  if ( x != static_cast<double>(r) ) return r;
136  return 2*(r/2);
137  }
138  else
139  {
140  x-=0.5;
141  const int r = static_cast<int>(x);
142  if ( x != static_cast<double>(r) ) return r;
143  return 2*(r/2);
144  }
145 }
146 
147 #endif
148 
149 
150 
151 // vil_round_rnd_halfintup -- round towards nearest integer
152 // halfway cases are rounded upward, e.g.
153 // vil_round_rnd_halfintup( 1.5) == 2
154 // vil_round_rnd_halfintup(-1.5) == -1
155 // vil_round_rnd_halfintup( 2.5) == 3
156 //
157 // Be careful: argument absolute value must be less than INT_MAX/2
158 // for vil_round_rnd_halfintup to be guaranteed to work.
159 // We also assume that the rounding mode is not changed from the default
160 // one (or at least that it is always restored to the default one).
161 
162 #if VIL_CONFIG_ENABLE_SSE2_ROUNDING || GCC_USE_FAST_IMPL || VC_USE_FAST_IMPL
163 
164 inline int vil_round_rnd_halfintup(float x) { return vil_round_rnd_halfinttoeven(2*x+0.5f)>>1; }
165 inline int vil_round_rnd_halfintup(double x) { return vil_round_rnd_halfinttoeven(2*x+0.5)>>1; }
166 
167 #else // Vanilla implementation
168 
169 inline int vil_round_rnd_halfintup(float x)
170 {
171  x+=0.5f;
172  return static_cast<int>(x>=0.f?x:(x==static_cast<int>(x)?x:x-1.f));
173 }
174 inline int vil_round_rnd_halfintup(double x)
175 {
176  x+=0.5;
177  return static_cast<int>(x>=0.?x:(x==static_cast<int>(x)?x:x-1.));
178 }
179 
180 #endif
181 
182 
183 
184 // vil_round_rnd -- round towards nearest integer
185 // halfway cases such as 0.5 may be rounded either up or down
186 // so as to maximize the efficiency, e.g.
187 // vil_round_rnd_halfinttoeven( 1.5) == 1 or 2
188 // vil_round_rnd_halfinttoeven(-1.5) == -2 or -1
189 // vil_round_rnd_halfinttoeven( 2.5) == 2 or 3
190 // vil_round_rnd_halfinttoeven( 3.5) == 3 or 4
191 //
192 // We assume that the rounding mode is not changed from the default
193 // one (or at least that it is always restored to the default one).
194 
195 #if VIL_CONFIG_ENABLE_SSE2_ROUNDING || GCC_USE_FAST_IMPL || VC_USE_FAST_IMPL
196 
197 inline int vil_round_rnd(float x) { return vil_round_rnd_halfinttoeven(x); }
198 inline int vil_round_rnd(double x) { return vil_round_rnd_halfinttoeven(x); }
199 
200 #else // Vanilla implementation
201 
202 inline int vil_round_rnd(float x) { return x>=0.f?static_cast<int>(x+.5f):static_cast<int>(x-.5f); }
203 inline int vil_round_rnd(double x) { return x>=0.0?static_cast<int>(x+0.5):static_cast<int>(x-0.5); }
204 
205 
206 #endif
207 
208 
209 
210 // vil_round_floor -- round towards minus infinity
211 //
212 // Be careful: argument absolute value must be less than INT_MAX/2
213 // for vil_round_floor to be guaranteed to work.
214 // We also assume that the rounding mode is not changed from the default
215 // one (or at least that it is always restored to the default one).
216 
217 #if VIL_CONFIG_ENABLE_SSE2_ROUNDING // Fast sse2 implementation
218 
219 inline int vil_round_floor(float x)
220 {
221 # if defined(VIL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__)
222  assert(fegetround()==FE_TONEAREST);
223 # endif
224  return _mm_cvtss_si32(_mm_set_ss(2*x-.5f))>>1;
225 }
226 inline int vil_round_floor(double x)
227 {
228 # if defined(VIL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__)
229  assert(fegetround()==FE_TONEAREST);
230 # endif
231  return _mm_cvtsd_si32(_mm_set_sd(2*x-.5))>>1;
232 }
233 
234 #elif GCC_USE_FAST_IMPL // Fast gcc asm implementation
235 
236 inline int vil_round_floor(float x)
237 {
238 # ifdef VIL_CHECK_FPU_ROUNDING_MODE
239  assert(fegetround()==FE_TONEAREST);
240 # endif
241  int r;
242  x = 2*x-.5f;
243  __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st");
244  return r>>1;
245 }
246 inline int vil_round_floor(double x)
247 {
248 # ifdef VIL_CHECK_FPU_ROUNDING_MODE
249  assert(fegetround()==FE_TONEAREST);
250 # endif
251  int r;
252  x = 2*x-.5;
253  __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st");
254  return r>>1;
255 }
256 
257 #elif VC_USE_FAST_IMPL // Fast msvc asm implementation
258 
259 inline int vil_round_floor(float x)
260 {
261  int r;
262  x = 2*x-.5f;
263  __asm {
264  fld x
265  fistp r
266  }
267  return r>>1;
268 }
269 inline int vil_round_floor(double x)
270 {
271  int r;
272  x = 2*x-.5;
273  __asm {
274  fld x
275  fistp r
276  }
277  return r>>1;
278 }
279 
280 #else // Vanilla implementation
281 
282 inline int vil_round_floor(float x)
283 {
284  return static_cast<int>(x>=0.f?x:(x==static_cast<int>(x)?x:x-1.f));
285 }
286 inline int vil_round_floor(double x)
287 {
288  return static_cast<int>(x>=0.0?x:(x==static_cast<int>(x)?x:x-1.0));
289 }
290 
291 #endif
292 
293 
294 
295 // vil_round_ceil -- round towards plus infinity
296 //
297 // Be careful: argument absolute value must be less than INT_MAX/2
298 // for vil_round_ceil to be guaranteed to work.
299 // We also assume that the rounding mode is not changed from the default
300 // one (or at least that it is always restored to the default one).
301 
302 #if VIL_CONFIG_ENABLE_SSE2_ROUNDING // Fast sse2 implementation
303 
304 inline int vil_round_ceil(float x)
305 {
306 # if defined(VIL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__)
307  assert(fegetround()==FE_TONEAREST);
308 # endif
309  return -(_mm_cvtss_si32(_mm_set_ss(-.5f-2*x))>>1);
310 }
311 inline int vil_round_ceil(double x)
312 {
313 # if defined(VIL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__)
314  assert(fegetround()==FE_TONEAREST);
315 # endif
316  return -(_mm_cvtsd_si32(_mm_set_sd(-.5-2*x))>>1);
317 }
318 
319 #elif GCC_USE_FAST_IMPL // Fast gcc asm implementation
320 
321 inline int vil_round_ceil(float x)
322 {
323 # ifdef VIL_CHECK_FPU_ROUNDING_MODE
324  assert(fegetround()==FE_TONEAREST);
325 # endif
326  int r;
327  x = -.5f-2*x;
328  __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st");
329  return -(r>>1);
330 }
331 inline int vil_round_ceil(double x)
332 {
333 # ifdef VIL_CHECK_FPU_ROUNDING_MODE
334  assert(fegetround()==FE_TONEAREST);
335 # endif
336  int r;
337  x = -.5-2*x;
338  __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st");
339  return -(r>>1);
340 }
341 
342 #elif VC_USE_FAST_IMPL // Fast msvc asm implementation
343 
344 inline int vil_round_ceil(float x)
345 {
346  int r;
347  x = -.5f-2*x;
348  __asm {
349  fld x
350  fistp r
351  }
352  return -(r>>1);
353 }
354 inline int vil_round_ceil(double x)
355 {
356  int r;
357  x = -.5-2*x;
358  __asm {
359  fld x
360  fistp r
361  }
362  return -(r>>1);
363 }
364 
365 #else // Vanilla implementation
366 
367 inline int vil_round_ceil(float x)
368 {
369  return static_cast<int>(x<0.f?x:(x==static_cast<int>(x)?x:x+1.f));
370 }
371 inline int vil_round_ceil(double x)
372 {
373  return static_cast<int>(x<0.0?x:(x==static_cast<int>(x)?x:x+1.0));
374 }
375 
376 #endif
377 
378 
379 #endif // vil_round_h_
int vil_round_floor(float x)
Definition: vil_round.h:282
int vil_round_rnd_halfintup(float x)
Definition: vil_round.h:169
int vil_round_ceil(float x)
Definition: vil_round.h:367
int vil_round_rnd_halfinttoeven(float x)
Definition: vil_round.h:112
int vil_round_rnd(float x)
Definition: vil_round.h:202