ITK 6.0.0
Insight Toolkit
 
Loading...
Searching...
No Matches
itkMathDetail.h
Go to the documentation of this file.
1/*=========================================================================
2 *
3 * Copyright NumFOCUS
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0.txt
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *=========================================================================*/
18/*=========================================================================
19 *
20 * Portions of this file are subject to the VTK Toolkit Version 3 copyright.
21 *
22 * Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
23 *
24 * For complete copyright, license and disclaimer of warranty information
25 * please refer to the NOTICE file at the top of the ITK source tree.
26 *
27 *=========================================================================*/
28#ifndef itkMathDetail_h
29#define itkMathDetail_h
30
31#include "itkIntTypes.h"
32#include "itkNumericTraits.h"
33
34#include <cfenv>
35
36#if (defined(ITK_COMPILER_SUPPORTS_SSE2_32) || defined(ITK_COMPILER_SUPPORTS_SSE2_64)) && !defined(ITK_WRAPPING_PARSER)
37# include <emmintrin.h> // SSE2 intrinsics
38#endif
39
40// Initially assume no SSE2:
41#define USE_SSE2_64IMPL 0
42#define USE_SSE2_32IMPL 0
43
44// Turn on 32-bit and/or 64-bit SSE2 impl when using any compiler on x86 platform.
45#if defined(ITK_COMPILER_SUPPORTS_SSE2_32) && !defined(ITK_WRAPPING_PARSER)
46# undef USE_SSE2_32IMPL
47# define USE_SSE2_32IMPL 1
48#endif
49#if defined(ITK_COMPILER_SUPPORTS_SSE2_64) && !defined(ITK_WRAPPING_PARSER)
50# undef USE_SSE2_64IMPL
51# define USE_SSE2_64IMPL 1
52#endif
53
54// Turn on 32-bit and 64-bit asm impl when using GCC/clang on x86 platform with the
55// following exception:
56// GCCXML
57#if defined(__GNUC__) && !defined(ITK_WRAPPING_PARSER) && \
58 (defined(__i386__) || defined(__i386) || defined(__x86_64__) || defined(__x86_64))
59# define GCC_USE_ASM_32IMPL 1
60# define GCC_USE_ASM_64IMPL 1
61#else
62# define GCC_USE_ASM_32IMPL 0
63# define GCC_USE_ASM_64IMPL 0
64#endif
65
66// Turn on 32-bit and 64-bit asm impl when using MSVC on 32-bit x86 Windows
67#if defined(_MSC_VER) && !defined(ITK_WRAPPING_PARSER) && !defined(_WIN64)
68# define VC_USE_ASM_32IMPL 1
69# define VC_USE_ASM_64IMPL 1
70#else
71# define VC_USE_ASM_32IMPL 0
72# define VC_USE_ASM_64IMPL 0
73#endif
74
75namespace itk
76{
77
78namespace Math::Detail
79{
80// The functions defined in this namespace are not meant to be used directly
81// and thus do not adhere to the standard backward-compatibility
82// policy of ITK, as any Detail namespace should be considered private.
83// Please use the functions from the itk::Math namespace instead
84
86// Base versions
87
88ITK_GCC_PRAGMA_PUSH
89ITK_GCC_SUPPRESS_Wfloat_equal
90
91template <typename TReturn, typename TInput>
92constexpr TReturn
94{
96 {
97 x += static_cast<TInput>(0.5);
98 }
99 else
100 {
101 x -= static_cast<TInput>(0.5);
102 }
103
104 const auto r = static_cast<TReturn>(x);
105 return (x != static_cast<TInput>(r)) ? r : static_cast<TReturn>(2 * (r / 2));
106}
107
108template <typename TReturn, typename TInput>
109constexpr TReturn
111{
112 x += static_cast<TInput>(0.5);
113 const auto r = static_cast<TReturn>(x);
115 : (x == static_cast<TInput>(r) ? r : r - static_cast<TReturn>(1));
116}
117
118template <typename TReturn, typename TInput>
119constexpr TReturn
120Floor_base(TInput x)
121{
122 const auto r = static_cast<TReturn>(x);
123
125 : (x == static_cast<TInput>(r) ? r : r - static_cast<TReturn>(1));
126}
127
128template <typename TReturn, typename TInput>
129constexpr TReturn
130Ceil_base(TInput x)
131{
132 const auto r = static_cast<TReturn>(x);
133
134 return (NumericTraits<TInput>::IsNegative(x)) ? r : (x == static_cast<TInput>(r) ? r : r + static_cast<TReturn>(1));
135}
136
137ITK_GCC_PRAGMA_POP
138
140// 32 bits versions
141
142#if USE_SSE2_32IMPL // SSE2 implementation
143
144inline int32_t
146{
147# if defined(ITK_CHECK_FPU_ROUNDING_MODE)
148 itkAssertInDebugAndIgnoreInReleaseMacro(fegetround() == FE_TONEAREST);
149# endif
150 return _mm_cvtsd_si32(_mm_set_sd(x));
151}
152
153inline int32_t
155{
156# if defined(ITK_CHECK_FPU_ROUNDING_MODE)
157 itkAssertInDebugAndIgnoreInReleaseMacro(fegetround() == FE_TONEAREST);
158# endif
159 return _mm_cvtss_si32(_mm_set_ss(x));
160}
161
162#elif GCC_USE_ASM_32IMPL // GCC/clang x86 asm implementation
163
164inline int32_t
166{
167# if defined(ITK_CHECK_FPU_ROUNDING_MODE)
168 itkAssertInDebugAndIgnoreInReleaseMacro(fegetround() == FE_TONEAREST);
169# endif
170 int32_t r;
171 __asm__ __volatile__("fistpl %0" : "=m"(r) : "t"(x) : "st");
172 return r;
173}
174
175inline int32_t
177{
178# if defined(ITK_CHECK_FPU_ROUNDING_MODE)
179 itkAssertInDebugAndIgnoreInReleaseMacro(fegetround() == FE_TONEAREST);
180# endif
181 int32_t r;
182 __asm__ __volatile__("fistpl %0" : "=m"(r) : "t"(x) : "st");
183 return r;
184}
185
186#elif VC_USE_ASM_32IMPL // msvc asm implementation
187
188inline int32_t
190{
191# if defined(ITK_CHECK_FPU_ROUNDING_MODE)
192 itkAssertInDebugAndIgnoreInReleaseMacro(fegetround() == FE_TONEAREST);
193# endif
194 int32_t r;
195 __asm
196 {
197 fld x
198 fistp r
199 }
200 return r;
201}
202
203inline int32_t
205{
206# if defined(ITK_CHECK_FPU_ROUNDING_MODE)
207 itkAssertInDebugAndIgnoreInReleaseMacro(fegetround() == FE_TONEAREST);
208# endif
209 int32_t r;
210 __asm
211 {
212 fld x
213 fistp r
214 }
215 return r;
216}
217
218#else // Base implementation
219
220template <typename TInput>
221constexpr int32_t
226
227#endif
228
229#if USE_SSE2_32IMPL || GCC_USE_ASM_32IMPL || VC_USE_ASM_32IMPL
230
231inline int32_t
232RoundHalfIntegerUp_32(double x)
233{
234 return RoundHalfIntegerToEven_32(2 * x + 0.5) >> 1;
235}
236inline int32_t
238{
239 return RoundHalfIntegerToEven_32(2 * x + 0.5f) >> 1;
240}
241
242inline int32_t
243Floor_32(double x)
244{
245 return RoundHalfIntegerToEven_32(2 * x - 0.5) >> 1;
246}
247inline int32_t
248Floor_32(float x)
249{
250 return RoundHalfIntegerToEven_32(2 * x - 0.5f) >> 1;
251}
252
253inline int32_t
254Ceil_32(double x)
255{
256 return -(RoundHalfIntegerToEven_32(-0.5 - 2 * x) >> 1);
257}
258inline int32_t
259Ceil_32(float x)
260{
261 return -(RoundHalfIntegerToEven_32(-0.5f - 2 * x) >> 1);
262}
263
264#else // Base implementation
265
266template <typename TInput>
267constexpr int32_t
272
273template <typename TInput>
274constexpr int32_t
275Floor_32(TInput x)
276{
278}
279
280template <typename TInput>
281constexpr int32_t
282Ceil_32(TInput x)
283{
285}
286
287#endif // USE_SSE2_32IMPL || GCC_USE_ASM_32IMPL || VC_USE_ASM_32IMPL
288
290// 64 bits versions
291
292#if USE_SSE2_64IMPL // SSE2 implementation
293
294inline int64_t
296{
297# if defined(ITK_CHECK_FPU_ROUNDING_MODE)
298 itkAssertInDebugAndIgnoreInReleaseMacro(fegetround() == FE_TONEAREST);
299# endif
300 return _mm_cvtsd_si64(_mm_set_sd(x));
301}
302
303inline int64_t
305{
306# if defined(ITK_CHECK_FPU_ROUNDING_MODE)
307 itkAssertInDebugAndIgnoreInReleaseMacro(fegetround() == FE_TONEAREST);
308# endif
309 return _mm_cvtss_si64(_mm_set_ss(x));
310}
311
312#elif GCC_USE_ASM_64IMPL // GCC/clang x86 asm implementation
313
314inline int64_t
316{
317# if defined(ITK_CHECK_FPU_ROUNDING_MODE)
318 itkAssertInDebugAndIgnoreInReleaseMacro(fegetround() == FE_TONEAREST);
319# endif
320 int64_t r;
321 __asm__ __volatile__("fistpll %0" : "=m"(r) : "t"(x) : "st");
322 return r;
323}
324
325inline int64_t
327{
328# if defined(ITK_CHECK_FPU_ROUNDING_MODE)
329 itkAssertInDebugAndIgnoreInReleaseMacro(fegetround() == FE_TONEAREST);
330# endif
331 int64_t r;
332 __asm__ __volatile__("fistpll %0" : "=m"(r) : "t"(x) : "st");
333 return r;
334}
335
336#elif VC_USE_ASM_64IMPL // msvc asm implementation
337
338inline int64_t
340{
341# if defined(ITK_CHECK_FPU_ROUNDING_MODE)
342 itkAssertInDebugAndIgnoreInReleaseMacro(fegetround() == FE_TONEAREST);
343# endif
344 int64_t r;
345 __asm
346 {
347 fld x
348 fistp r
349 }
350 return r;
351}
352
353inline int64_t
355{
356# if defined(ITK_CHECK_FPU_ROUNDING_MODE)
357 itkAssertInDebugAndIgnoreInReleaseMacro(fegetround() == FE_TONEAREST);
358# endif
359 int64_t r;
360 __asm
361 {
362 fld x
363 fistp r
364 }
365 return r;
366}
367
368#else // Base implementation
369
370template <typename TInput>
371constexpr int64_t
376
377#endif
378
379#if USE_SSE2_64IMPL || GCC_USE_ASM_64IMPL || VC_USE_ASM_64IMPL
380
381inline int64_t
382RoundHalfIntegerUp_64(double x)
383{
384 return RoundHalfIntegerToEven_64(2 * x + 0.5) >> 1;
385}
386inline int64_t
388{
389 return RoundHalfIntegerToEven_64(2 * x + 0.5f) >> 1;
390}
391
392inline int64_t
393Floor_64(double x)
394{
395 return RoundHalfIntegerToEven_64(2 * x - 0.5) >> 1;
396}
397inline int64_t
398Floor_64(float x)
399{
400 return RoundHalfIntegerToEven_64(2 * x - 0.5f) >> 1;
401}
402
403inline int64_t
404Ceil_64(double x)
405{
406 return -(RoundHalfIntegerToEven_64(-0.5 - 2 * x) >> 1);
407}
408inline int64_t
409Ceil_64(float x)
410{
411 return -(RoundHalfIntegerToEven_64(-0.5f - 2 * x) >> 1);
412}
413
414#else // Base implementation
415
416template <typename TInput>
417constexpr int64_t
422
423template <typename TInput>
424constexpr int64_t
425Floor_64(TInput x)
426{
428}
429
430template <typename TInput>
431constexpr int64_t
432Ceil_64(TInput x)
433{
435}
436
437#endif // USE_SSE2_64IMPL || GCC_USE_ASM_64IMPL || VC_USE_ASM_64IMPL
438
439template <typename T>
441
442template <>
443struct FloatIEEETraits<float>
444{
445 using IntType = int32_t;
446 using UIntType = uint32_t;
447};
448
449template <>
450struct FloatIEEETraits<double>
451{
452 using IntType = int64_t;
453 using UIntType = uint64_t;
454};
455
456template <typename T>
458{
459 using FloatType = T;
462
466
467 constexpr FloatIEEE(FloatType f)
468 : asFloat(f)
469 {}
470 constexpr FloatIEEE(IntType i)
471 : asInt(i)
472 {}
473 constexpr FloatIEEE(UIntType ui)
474 : asUInt(ui)
475 {}
476 [[nodiscard]] constexpr bool
477 Sign() const
478 {
479 return (asUInt >> (sizeof(asUInt) * 8 - 1)) != 0;
480 }
481 [[nodiscard]] constexpr IntType
482 AsULP() const
483 {
484 return this->Sign() ? IntType(~(~UIntType(0) >> 1) - asUInt) : asInt;
485 }
486};
487
488} // namespace Math::Detail
489// end namespace Math
490
491// move to itkConceptChecking?
492namespace Concept
493{
494template <typename T>
496template <>
497struct FloatOrDouble<float>
498{};
499template <>
500struct FloatOrDouble<double>
501{};
502} // end namespace Concept
503} // end namespace itk
504
505#undef USE_SSE2_32IMPL
506#undef GCC_USE_ASM_32IMPL
507#undef VC_USE_ASM_32IMPL
508
509#undef USE_SSE2_64IMPL
510#undef GCC_USE_ASM_64IMPL
511#undef VC_USE_ASM_64IMPL
512
513#endif // end of itkMathDetail.h
static bool IsNegative(T val)
static bool IsNonnegative(T val)
constexpr int32_t Floor_32(TInput x)
ITK_GCC_PRAGMA_POP constexpr int32_t RoundHalfIntegerToEven_32(TInput x)
constexpr int64_t RoundHalfIntegerToEven_64(TInput x)
constexpr int32_t RoundHalfIntegerUp_32(TInput x)
constexpr TReturn Floor_base(TInput x)
constexpr TReturn RoundHalfIntegerUp_base(TInput x)
ITK_GCC_PRAGMA_PUSH ITK_GCC_SUPPRESS_Wfloat_equal constexpr TReturn RoundHalfIntegerToEven_base(TInput x)
constexpr int64_t RoundHalfIntegerUp_64(TInput x)
constexpr int32_t Ceil_32(TInput x)
constexpr int64_t Ceil_64(TInput x)
constexpr int64_t Floor_64(TInput x)
constexpr TReturn Ceil_base(TInput x)
The "itk" namespace contains all Insight Segmentation and Registration Toolkit (ITK) classes....
constexpr bool Sign() const
constexpr FloatIEEE(IntType i)
constexpr IntType AsULP() const
constexpr FloatIEEE(FloatType f)
constexpr FloatIEEE(UIntType ui)
typename FloatIEEETraits< T >::IntType IntType
typename FloatIEEETraits< T >::UIntType UIntType