1 // This is core/vnl/vnl_math.h
2 #ifndef vnl_math_h_
3 #define vnl_math_h_
4 //:
5 // \file
6 // \brief Namespace with standard math functions
7 //
8 //  The vnl_math namespace provides a standard set of the simple mathematical
9 //  functions (min, max, sqr, sgn, rnd, abs), and some predefined constants
10 //  such as pi and e, which are not defined by the ANSI C++ standard.
11 //
12 //  There are complex versions defined in vnl_complex.h
13 //
14 //  That's right, M_PI is nonstandard!
15 //
16 //  Aside from e, pi and their associates the namespace also defines eps,
17 //  the IEEE double machine precision.  This is the smallest number
18 //  eps such that 1+eps != 1.
19 //
20 //  The operations are overloaded for int, float and double arguments,
21 //  which in combination with inlining can make them  more efficient than
22 //  their counterparts in the standard C library.
23 //
24 // \author Andrew W. Fitzgibbon, Oxford RRG
25 // \date   July 13, 1996
26 //
27 // \verbatim
28 //  Modifications
29 //   21 May 1998 AWF Removed conditional VCL_IMPLEMENT_STATIC_CONSTS, sometimes gcc needs them.
30 //   LSB (Modifications) 23 Jan 2001 Documentation tidied
31 //   Peter Vanroose - 7 Sep 2002 - maxdouble etc. replaced by vnl_numeric_traits<T>::maxval
32 //   Amitha Perera - 13 Sep 2002 - make constant initialization standards compliant.
33 //   Peter Vanroose -22 Oct 2012 - was a class, now is a namespace
34 //                                 also renamed functions vnl_math_isnan etc. to vnl_math::isnan
35 // \endverbatim
36 
37 #include <cmath>
38 #include <algorithm>
39 #include <complex>
40 #ifdef _MSC_VER
41 #  include <vcl_msvc_warnings.h>
42 #endif
43 #include "dll.h"
44 #include <vxl_config.h>
45 #include <vnl/vnl_config.h> // for VNL_CONFIG_ENABLE_SSE2_ROUNDING
46 #include <vnl/vnl_export.h>
47 #ifdef VNL_CHECK_FPU_ROUNDING_MODE
48 #include <cassert>
49 #endif
50 
51 // Figure out when the fast implementation can be used
52 #if VNL_CONFIG_ENABLE_SSE2_ROUNDING && defined(__SSE2__)
53 # if !VXL_HAS_EMMINTRIN_H
54 #   error "Required file emmintrin.h for SSE2 not found"
55 # else
56 #   include <emmintrin.h> // sse 2 intrinsics
57 #   define USE_SSE2_IMPL 1
58 # endif
59 #else
60 # define USE_SSE2_IMPL 0
61 #endif
62 
63 // Turn on fast impl when using GCC on Intel-based machines with the following exception:
64 #if defined(__GNUC__) && ((defined(__i386__) || defined(__i386) || defined(__x86_64__) || defined(__x86_64)))
65 # define GCC_USE_FAST_IMPL 1
66 #else
67 # define GCC_USE_FAST_IMPL 0
68 #endif
69 // Turn on fast impl when using msvc on 32 bits windows
70 #if defined(_MSC_VER) && !defined(_WIN64)
71 # define VC_USE_FAST_IMPL 1
72 #else
73 # define VC_USE_FAST_IMPL 0
74 #endif
75 
76 
77 
78 //: Type-accessible infinities for use in templates.
79 template <class T> VNL_EXPORT T vnl_huge_val(T);
80 extern VNL_EXPORT long double   vnl_huge_val(long double);
81 extern VNL_EXPORT double   vnl_huge_val(double);
82 extern VNL_EXPORT float    vnl_huge_val(float);
83 extern VNL_EXPORT long int vnl_huge_val(long int);
84 extern VNL_EXPORT int      vnl_huge_val(int);
85 extern VNL_EXPORT short    vnl_huge_val(short);
86 extern VNL_EXPORT char     vnl_huge_val(char);
87 
88 //: real numerical constants
89 // Strictly speaking, the static declaration of the constant variables is
90 // redundant with the implicit behavior in C++ of objects declared const
91 // as defined at:
92 //  "C++98 7.1.1/6: ...Objects declared const and not explicitly declared
93 //   extern have internal linkage."
94 //
95 // Explicit use of the static keyword is used to make the code easier to
96 // understand.
97 namespace vnl_math
98 {
99   //: pi, e and all that.  Constants are rounded to the shown precision.
100   static constexpr double e                = 2.71828182845904523536; // http://oeis.org/A001113
101   static constexpr double log2e            = 1.44269504088896340736; // http://oeis.org/A007525
102   static constexpr double log10e           = 0.43429448190325182765; // http://oeis.org/A002285
103   static constexpr double ln2              = 0.69314718055994530942; // http://oeis.org/A002162
104   static constexpr double ln10             = 2.30258509299404568402; // http://oeis.org/A002392
105   static constexpr double pi               = 3.14159265358979323846; // http://oeis.org/A000796
106   static constexpr double twopi            = 6.28318530717958647693; // http://oeis.org/A019692
107   static constexpr double pi_over_2        = 1.57079632679489661923; // http://oeis.org/A019669
108   static constexpr double pi_over_4        = 0.78539816339744830962; // http://oeis.org/A003881
109   static constexpr double pi_over_180      = 0.01745329251994329577; // http://oeis.org/A019685
110   static constexpr double one_over_pi      = 0.31830988618379067154; // http://oeis.org/A049541
111   static constexpr double two_over_pi      = 0.63661977236758134308; // http://oeis.org/A060294
112   static constexpr double deg_per_rad      = 57.2957795130823208768; // http://oeis.org/A072097
113   static constexpr double sqrt2pi          = 2.50662827463100050242; // http://oeis.org/A019727
114   static constexpr double two_over_sqrtpi  = 1.12837916709551257390; // http://oeis.org/A190732
115   static constexpr double one_over_sqrt2pi = 0.39894228040143267794; // http://oeis.org/A231863
116   static constexpr double sqrt2            = 1.41421356237309504880; // http://oeis.org/A002193
117   static constexpr double sqrt1_2          = 0.70710678118654752440; // http://oeis.org/A010503
118   static constexpr double sqrt1_3          = 0.57735026918962576451; // http://oeis.org/A020760
119   static constexpr double euler            = 0.57721566490153286061; // http://oeis.org/A001620
120 
121   //: IEEE double machine precision
122   static constexpr double eps              = 2.2204460492503131e-16;
123   static constexpr double sqrteps          = 1.490116119384766e-08;
124   //: IEEE single machine precision
125   static constexpr float  float_eps        = 1.192092896e-07f;
126   static constexpr float  float_sqrteps    = 3.4526698300e-4f;
127 
128   //: Convert an angle to [0, 2Pi) range
129   VNL_EXPORT double angle_0_to_2pi(double angle);
130   //: Convert an angle to [-Pi, Pi) range
131   VNL_EXPORT double angle_minuspi_to_pi(double angle);
132 }
133 
134 // Note that the three template functions below should not be declared "inline"
135 // since that would override the non-inline specialisations. - PVr.
136 //
137 
138 namespace vnl_math
139 {
140 #if defined(_MSC_VER)
141   // MSVC does not properly implement isfinite, iinf, isnan for C++11 conformance for integral types
142   // For integral types only:
143   template<typename T>
isnan(_In_ T t)144   _Check_return_ typename std::enable_if<std::is_integral<T>::value, bool>::type isnan(_In_ T t) throw()
145   {
146     return std::isnan(static_cast<double>(t));
147   }
148   template<typename T>
isinf(_In_ T t)149   _Check_return_ typename std::enable_if<std::is_integral<T>::value, bool>::type isinf(_In_ T t) throw()
150   {
151     return std::isinf(static_cast<double>(t));
152   }
153   template<typename T>
isfinite(_In_ T t)154   _Check_return_ typename std::enable_if<std::is_integral<T>::value, bool>::type isfinite(_In_ T t) throw()
155   {
156     return std::isfinite(static_cast<double>(t));
157   }
158   template<typename T>
isnormal(_In_ T t)159   _Check_return_ typename std::enable_if<std::is_integral<T>::value, bool>::type isnormal(_In_ T t) throw()
160   {
161     return std::isnormal(static_cast<double>(t));
162   }
163 
164   // Floating point types can alias C++ standard that is implemented
165   template<typename T>
isnan(_In_ T t)166   _Check_return_ typename std::enable_if<std::is_floating_point<T>::value, bool>::type isnan(_In_ T t) throw()
167   {
168 	  return std::isnan(t);
169   }
170   template<typename T>
isinf(_In_ T t)171   _Check_return_ typename std::enable_if<std::is_floating_point<T>::value, bool>::type isinf(_In_ T t) throw()
172   {
173 	  return std::isinf(t);
174   }
175   template<typename T>
isfinite(_In_ T t)176   _Check_return_ typename std::enable_if<std::is_floating_point<T>::value, bool>::type isfinite(_In_ T t) throw()
177   {
178 	  return std::isfinite(t);
179   }
180   template<typename T>
isnormal(_In_ T t)181   _Check_return_ typename std::enable_if<std::is_floating_point<T>::value, bool>::type isnormal(_In_ T t) throw()
182   {
183 	  return std::isnormal(t);
184   }
185 #else
186   // https://en.cppreference.com/w/cpp/numeric/math/isinf indicates that isinf should return bool
187   // However, several compiler environments do not properly conform to the C++11 standard for
188   // returning bool from these functions.  Wrap them to ensure conformance, and
189   // rely on the compiler to optimize the overhead away.
190 
191   // Return a signed integer type has been seen with the following
192   // compilers/libstdc++:
193   //  RHEL7-devtool-6-gcc6.3
194   //  RHEL7-devtool-6-gcc6.3-m32
195   //  RHEL7-devtool-7-gcc7.2
196   // 	RHEL7-devtool-7-gcc7.2-m32
197 
198   template <typename TArg>
199   inline bool isinf(TArg arg) { return bool(std::isinf(arg)); }
200   template <typename TArg>
201   inline bool isnan(TArg arg) { return bool(std::isnan(arg)); }
202   template <typename TArg>
203   inline bool isfinite(TArg arg) { return bool(std::isfinite(arg)); }
204   template <typename TArg>
205   inline bool isnormal(TArg arg) { return bool(std::isnormal(arg)); }
206 #endif
207   using std::max;
208   using std::min;
209   using std::cbrt;
210 #if 0 // Use std::cbrt
211   template <typename TArg>
212   TArg cuberoot(TArg&& arg)
213     {
214     return std::cbrt(std::forward<TArg>(arg));
215     }
216 #endif
217   using std::hypot;
218 
219 #if USE_SSE2_IMPL // Fast sse2 implementation
220 
221 // rnd_halfinttoeven  -- round towards nearest integer
222 //         halfway cases are rounded towards the nearest even integer, e.g.
223 //         rnd_halfinttoeven( 1.5) ==  2
224 //         rnd_halfinttoeven(-1.5) == -2
225 //         rnd_halfinttoeven( 2.5) ==  2
226 //         rnd_halfinttoeven( 3.5) ==  4
227 //
228 // We assume that the rounding mode is not changed from the default
229 // one (or at least that it is always restored to the default one).
rnd_halfinttoeven(float x)230 inline int rnd_halfinttoeven(float  x)
231 {
232 # if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__)
233   assert(fegetround()==FE_TONEAREST);
234 # endif
235   return _mm_cvtss_si32(_mm_set_ss(x));
236 }
237 
rnd_halfinttoeven(double x)238 inline int rnd_halfinttoeven(double  x)
239 {
240 # if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__)
241   assert(fegetround()==FE_TONEAREST);
242 # endif
243   return _mm_cvtsd_si32(_mm_set_sd(x));
244 }
245 
246 #elif GCC_USE_FAST_IMPL // Fast gcc asm implementation
247 
rnd_halfinttoeven(float x)248 inline int rnd_halfinttoeven(float  x)
249 {
250 # ifdef VNL_CHECK_FPU_ROUNDING_MODE
251   assert(fegetround()==FE_TONEAREST);
252 # endif
253   int r;
254   __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st");
255   return r;
256 }
257 
rnd_halfinttoeven(double x)258 inline int rnd_halfinttoeven(double  x)
259 {
260 # ifdef VNL_CHECK_FPU_ROUNDING_MODE
261   assert(fegetround()==FE_TONEAREST);
262 # endif
263   int r;
264   __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st");
265   return r;
266 }
267 
268 #elif VC_USE_FAST_IMPL // Fast msvc asm implementation
269 
rnd_halfinttoeven(float x)270 inline int rnd_halfinttoeven(float  x)
271 {
272   int r;
273   __asm {
274     fld x
275     fistp r
276   }
277   return r;
278 }
279 
rnd_halfinttoeven(double x)280 inline int rnd_halfinttoeven(double  x)
281 {
282   int r;
283   __asm {
284     fld x
285     fistp r
286   }
287   return r;
288 }
289 
290 #else // Vanilla implementation
291 
rnd_halfinttoeven(float x)292 inline int rnd_halfinttoeven(float  x)
293 {
294   if (x>=0.f)
295   {
296      x+=0.5f;
297      const int r = static_cast<int>(x);
298      if ( x != static_cast<float>(r) ) return r;
299      return 2*(r/2);
300   }
301   else
302   {
303      x-=0.5f;
304      const int r = static_cast<int>(x);
305      if ( x != static_cast<float>(r) ) return r;
306      return 2*(r/2);
307   }
308 }
309 
rnd_halfinttoeven(double x)310 inline int rnd_halfinttoeven(double x)
311 {
312   if (x>=0.)
313   {
314      x+=0.5;
315      const int r = static_cast<int>(x);
316      if ( x != static_cast<double>(r) ) return r;
317      return 2*(r/2);
318   }
319   else
320   {
321      x-=0.5;
322      const int r = static_cast<int>(x);
323      if ( x != static_cast<double>(r) ) return r;
324      return 2*(r/2);
325   }
326 }
327 
328 #endif
329 
330 
331 #if USE_SSE2_IMPL || GCC_USE_FAST_IMPL || VC_USE_FAST_IMPL
332 
333 // rnd_halfintup  -- round towards nearest integer
334 //         halfway cases are rounded upward, e.g.
335 //         rnd_halfintup( 1.5) ==  2
336 //         rnd_halfintup(-1.5) == -1
337 //         rnd_halfintup( 2.5) ==  3
338 //
339 // Be careful: argument absolute value must be less than INT_MAX/2
340 // for rnd_halfintup to be guaranteed to work.
341 // We also assume that the rounding mode is not changed from the default
342 // one (or at least that it is always restored to the default one).
343 
rnd_halfintup(float x)344 inline int rnd_halfintup(float  x) { return rnd_halfinttoeven(2*x+0.5f)>>1; }
rnd_halfintup(double x)345 inline int rnd_halfintup(double  x) { return rnd_halfinttoeven(2*x+0.5)>>1; }
346 
347 #else // Vanilla implementation
348 
rnd_halfintup(float x)349 inline int rnd_halfintup(float  x)
350 {
351   x+=0.5f;
352   return static_cast<int>(x>=0.f?x:(x==static_cast<int>(x)?x:x-1.f));
353 }
354 
rnd_halfintup(double x)355 inline int rnd_halfintup(double x)
356 {
357   x+=0.5;
358   return static_cast<int>(x>=0.?x:(x==static_cast<int>(x)?x:x-1.));
359 }
360 
361 #endif
362 
363 #if  USE_SSE2_IMPL || GCC_USE_FAST_IMPL || VC_USE_FAST_IMPL
364 // rnd  -- round towards nearest integer
365 //         halfway cases such as 0.5 may be rounded either up or down
366 //         so as to maximize the efficiency, e.g.
367 //         rnd_halfinttoeven( 1.5) ==  1 or  2
368 //         rnd_halfinttoeven(-1.5) == -2 or -1
369 //         rnd_halfinttoeven( 2.5) ==  2 or  3
370 //         rnd_halfinttoeven( 3.5) ==  3 or  4
371 //
372 // We assume that the rounding mode is not changed from the default
373 // one (or at least that it is always restored to the default one).
rnd(float x)374 inline int rnd(float  x) { return rnd_halfinttoeven(x); }
rnd(double x)375 inline int rnd(double  x) { return rnd_halfinttoeven(x); }
376 
377 #else // Vanilla implementation
378 
rnd(float x)379 inline int rnd(float  x) { return x>=0.f?static_cast<int>(x+.5f):static_cast<int>(x-.5f); }
rnd(double x)380 inline int rnd(double x) { return x>=0.0?static_cast<int>(x+0.5):static_cast<int>(x-0.5); }
381 
382 #endif
383 
384 #if  USE_SSE2_IMPL // Fast sse2 implementation
385 // floor -- round towards minus infinity
386 //
387 // Be careful: argument absolute value must be less than INT_MAX/2
388 // for floor to be guaranteed to work.
389 // We also assume that the rounding mode is not changed from the default
390 // one (or at least that it is always restored to the default one).
391 
floor(float x)392 inline int floor(float  x)
393 {
394 # if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__)
395   assert(fegetround()==FE_TONEAREST);
396 # endif
397    return _mm_cvtss_si32(_mm_set_ss(2*x-.5f))>>1;
398 }
399 
floor(double x)400 inline int floor(double  x)
401 {
402 # if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__)
403   assert(fegetround()==FE_TONEAREST);
404 # endif
405    return _mm_cvtsd_si32(_mm_set_sd(2*x-.5))>>1;
406 }
407 
408 #elif GCC_USE_FAST_IMPL // Fast gcc asm implementation
409 
floor(float x)410 inline int floor(float  x)
411 {
412 # ifdef VNL_CHECK_FPU_ROUNDING_MODE
413   assert(fegetround()==FE_TONEAREST);
414 # endif
415   int r;
416   x = 2*x-.5f;
417   __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st");
418   return r>>1;
419 }
420 
floor(double x)421 inline int floor(double  x)
422 {
423 # ifdef VNL_CHECK_FPU_ROUNDING_MODE
424   assert(fegetround()==FE_TONEAREST);
425 # endif
426   int r;
427   x = 2*x-.5;
428   __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st");
429   return r>>1;
430 }
431 
432 #elif VC_USE_FAST_IMPL // Fast msvc asm implementation
433 
floor(float x)434 inline int floor(float  x)
435 {
436   int r;
437   x = 2*x-.5f;
438   __asm {
439     fld x
440     fistp r
441   }
442   return r>>1;
443 }
444 
floor(double x)445 inline int floor(double  x)
446 {
447   int r;
448   x = 2*x-.5;
449   __asm {
450     fld x
451     fistp r
452   }
453   return r>>1;
454 }
455 
456 #else // Vanilla implementation
457 
floor(float x)458 inline int floor(float  x)
459 {
460   return static_cast<int>(x>=0.f?x:(x==static_cast<int>(x)?x:x-1.f));
461 }
462 
floor(double x)463 inline int floor(double x)
464 {
465   return static_cast<int>(x>=0.0?x:(x==static_cast<int>(x)?x:x-1.0));
466 }
467 
468 #endif
469 
470 
471 #if  USE_SSE2_IMPL // Fast sse2 implementation
472 // ceil -- round towards plus infinity
473 //
474 // Be careful: argument absolute value must be less than INT_MAX/2
475 // for ceil to be guaranteed to work.
476 // We also assume that the rounding mode is not changed from the default
477 // one (or at least that it is always restored to the default one).
478 
ceil(float x)479 inline int ceil(float  x)
480 {
481 # if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__)
482   assert(fegetround()==FE_TONEAREST);
483 # endif
484    return -(_mm_cvtss_si32(_mm_set_ss(-.5f-2*x))>>1);
485 }
486 
ceil(double x)487 inline int ceil(double  x)
488 {
489 # if defined(VNL_CHECK_FPU_ROUNDING_MODE) && defined(__GNUC__)
490   assert(fegetround()==FE_TONEAREST);
491 # endif
492    return -(_mm_cvtsd_si32(_mm_set_sd(-.5-2*x))>>1);
493 }
494 
495 #elif GCC_USE_FAST_IMPL // Fast gcc asm implementation
496 
ceil(float x)497 inline int ceil(float  x)
498 {
499 # ifdef VNL_CHECK_FPU_ROUNDING_MODE
500   assert(fegetround()==FE_TONEAREST);
501 # endif
502   int r;
503   x = -.5f-2*x;
504   __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st");
505   return -(r>>1);
506 }
507 
ceil(double x)508 inline int ceil(double  x)
509 {
510 # ifdef VNL_CHECK_FPU_ROUNDING_MODE
511   assert(fegetround()==FE_TONEAREST);
512 # endif
513   int r;
514   x = -.5-2*x;
515   __asm__ __volatile__ ("fistpl %0" : "=m"(r) : "t"(x) : "st");
516   return -(r>>1);
517 }
518 
519 #elif VC_USE_FAST_IMPL // Fast msvc asm implementation
520 
ceil(float x)521 inline int ceil(float  x)
522 {
523   int r;
524   x = -.5f-2*x;
525   __asm {
526     fld x
527     fistp r
528   }
529   return -(r>>1);
530 }
531 
ceil(double x)532 inline int ceil(double  x)
533 {
534   int r;
535   x = -.5-2*x;
536   __asm {
537     fld x
538     fistp r
539   }
540   return -(r>>1);
541 }
542 
543 #else // Vanilla implementation
544 
ceil(float x)545 inline int ceil(float  x)
546 {
547   return static_cast<int>(x<0.f?x:(x==static_cast<int>(x)?x:x+1.f));
548 }
549 
ceil(double x)550 inline int ceil(double x)
551 {
552   return static_cast<int>(x<0.0?x:(x==static_cast<int>(x)?x:x+1.0));
553 }
554 
555 #endif
556 
557 // abs
abs(bool x)558 inline bool               abs(bool x)               { return x; }
abs(unsigned char x)559 inline unsigned char      abs(unsigned char x)      { return x; }
abs(signed char x)560 inline unsigned char      abs(signed char x)        { return x < 0 ? static_cast<unsigned char>(-x) : x; }
abs(char x)561 inline unsigned char      abs(char x)               { return static_cast<unsigned char>(x); }
abs(short x)562 inline unsigned short     abs(short x)              { return x < 0 ? static_cast<unsigned short>(-x) : x; }
abs(unsigned short x)563 inline unsigned short     abs(unsigned short x)     { return x; }
abs(int x)564 inline unsigned int       abs(int x)                { return x < 0 ? -x : x; }
abs(unsigned int x)565 inline unsigned int       abs(unsigned int x)       { return x; }
abs(long x)566 inline unsigned long      abs(long x)               { return x < 0L ? -x : x; }
abs(unsigned long x)567 inline unsigned long      abs(unsigned long x)      { return x; }
568 //long long - target type will have width of at least 64 bits. (since C++11)
abs(long long x)569 inline unsigned long long abs(long long x)          { return x < 0LL ? -x : x; }
abs(unsigned long long x)570 inline unsigned long long abs(unsigned long long x) { return x; }
571 
abs(float x)572 inline float              abs(float x)              { return x < 0.0f ? -x : x; }
abs(double x)573 inline double             abs(double x)             { return x < 0.0 ? -x : x; }
abs(long double x)574 inline long double        abs(long double x)        { return x < 0.0 ? -x : x; }
575 
576 // sqr (square)
sqr(bool x)577 inline bool               sqr(bool x)               { return x; }
sqr(int x)578 inline int                sqr(int x)                { return x*x; }
sqr(unsigned int x)579 inline unsigned int       sqr(unsigned int x)       { return x*x; }
sqr(long x)580 inline long               sqr(long x)               { return x*x; }
sqr(unsigned long x)581 inline unsigned long      sqr(unsigned long x)      { return x*x; }
582 //long long - target type will have width of at least 64 bits. (since C++11)
sqr(long long x)583 inline long long          sqr(long long x)          { return x*x; }
sqr(unsigned long long x)584 inline unsigned long long sqr(unsigned long long x) { return x*x; }
585 
sqr(float x)586 inline float              sqr(float x)              { return x*x; }
sqr(double x)587 inline double             sqr(double x)             { return x*x; }
588 
589 // cube
cube(bool x)590 inline bool               cube(bool x)               { return x; }
cube(int x)591 inline int                cube(int x)                { return x*x*x; }
cube(unsigned int x)592 inline unsigned int       cube(unsigned int x)       { return x*x*x; }
cube(long x)593 inline long               cube(long x)               { return x*x*x; }
cube(unsigned long x)594 inline unsigned long      cube(unsigned long x)      { return x*x*x; }
595 //long long - target type will have width of at least 64 bits. (since C++11)
cube(long long x)596 inline long long          cube(long long x)          { return x*x*x; }
cube(unsigned long long x)597 inline unsigned long long cube(unsigned long long x) { return x*x*x; }
598 
cube(float x)599 inline float              cube(float x)              { return x*x*x; }
cube(double x)600 inline double             cube(double x)             { return x*x*x; }
601 
602 // sgn (sign in -1, 0, +1)
sgn(int x)603 inline int sgn(int x)       { return x?((x>0)?1:-1):0; }
sgn(long x)604 inline int sgn(long x)      { return x?((x>0)?1:-1):0; }
605 //long long - target type will have width of at least 64 bits. (since C++11)
sgn(long long x)606 inline int sgn(long long x) { return x?((x>0)?1:-1):0; }
607 
sgn(float x)608 inline int sgn(float x)     { return (x != 0)?((x>0)?1:-1):0; }
sgn(double x)609 inline int sgn(double x)    { return (x != 0)?((x>0)?1:-1):0; }
610 
611 // sgn0 (sign in -1, +1 only, useful for reals)
sgn0(int x)612 inline int sgn0(int x)         { return (x>=0)?1:-1; }
sgn0(long x)613 inline int sgn0(long x)        { return (x>=0)?1:-1; }
614 //long long - target type will have width of at least 64 bits. (since C++11)
sgn0(long long x)615 inline int sgn0(long long x)   { return (x>=0)?1:-1; }
616 
sgn0(float x)617 inline int sgn0(float x)       { return (x>=0)?1:-1; }
sgn0(double x)618 inline int sgn0(double x)      { return (x>=0)?1:-1; }
619 
620 // squared_magnitude
squared_magnitude(char x)621 inline unsigned int       squared_magnitude(char               x) { return int(x)*int(x); }
squared_magnitude(unsigned char x)622 inline unsigned int       squared_magnitude(unsigned char      x) { return int(x)*int(x); }
squared_magnitude(int x)623 inline unsigned int       squared_magnitude(int                x) { return x*x; }
squared_magnitude(unsigned int x)624 inline unsigned int       squared_magnitude(unsigned int       x) { return x*x; }
squared_magnitude(long x)625 inline unsigned long      squared_magnitude(long               x) { return x*x; }
squared_magnitude(unsigned long x)626 inline unsigned long      squared_magnitude(unsigned long      x) { return x*x; }
627 //long long - target type will have width of at least 64 bits. (since C++11)
squared_magnitude(long long x)628 inline unsigned long long squared_magnitude(long long          x) { return x*x; }
squared_magnitude(unsigned long long x)629 inline unsigned long long squared_magnitude(unsigned long long x) { return x*x; }
630 
squared_magnitude(float x)631 inline float              squared_magnitude(float              x) { return x*x; }
squared_magnitude(double x)632 inline double             squared_magnitude(double             x) { return x*x; }
squared_magnitude(long double x)633 inline long double        squared_magnitude(long double        x) { return x*x; }
634 
635 
636 // truncated remainder
remainder_truncated(int x,int y)637 inline int                remainder_truncated(int x, int y)                               { return x % y; }
remainder_truncated(unsigned int x,unsigned int y)638 inline unsigned int       remainder_truncated(unsigned int x, unsigned int y)             { return x % y; }
remainder_truncated(long x,long y)639 inline long               remainder_truncated(long x, long y)                             { return x % y; }
remainder_truncated(unsigned long x,unsigned long y)640 inline unsigned long      remainder_truncated(unsigned long x, unsigned long y)           { return x % y; }
remainder_truncated(long long x,long long y)641 inline long long          remainder_truncated(long long x, long long y)                   { return x % y; }
remainder_truncated(unsigned long long x,unsigned long long y)642 inline unsigned long long remainder_truncated(unsigned long long x, unsigned long long y) { return x % y; }
remainder_truncated(float x,float y)643 inline float              remainder_truncated(float x, float y)                           { return fmod(x,y); }
remainder_truncated(double x,double y)644 inline double             remainder_truncated(double x, double y)                         { return fmod(x,y); }
remainder_truncated(long double x,long double y)645 inline long double        remainder_truncated(long double x, long double y)               { return fmod(x,y); }
646 
647 // floored remainder
remainder_floored(int x,int y)648 inline int                remainder_floored(int x, int y)                               { return ((x % y) + y) % y; }
remainder_floored(unsigned int x,unsigned int y)649 inline unsigned int       remainder_floored(unsigned int x, unsigned int y)             { return x % y; }
remainder_floored(long x,long y)650 inline long               remainder_floored(long x, long y)                             { return ((x % y) + y) % y; }
remainder_floored(unsigned long x,unsigned long y)651 inline unsigned long      remainder_floored(unsigned long x, unsigned long y)           { return x % y; }
remainder_floored(long long x,long long y)652 inline long long          remainder_floored(long long x, long long y)                   { return ((x % y) + y) % y; }
remainder_floored(unsigned long long x,unsigned long long y)653 inline unsigned long long remainder_floored(unsigned long long x, unsigned long long y) { return x % y; }
remainder_floored(float x,float y)654 inline float              remainder_floored(float x, float y)                           { return fmod(fmod(x,y)+y,y); }
remainder_floored(double x,double y)655 inline double             remainder_floored(double x, double y)                         { return fmod(fmod(x,y)+y,y); }
remainder_floored(long double x,long double y)656 inline long double        remainder_floored(long double x, long double y)               { return fmod(fmod(x,y)+y,y); }
657 
658 } // end of namespace vnl_math
659 #endif // vnl_math_h_
660