FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
math.hpp
1// FEAT3: Finite Element Analysis Toolbox, Version 3
2// Copyright (C) 2010 by Stefan Turek & the FEAT group
3// FEAT3 is released under the GNU General Public License version 3,
4// see the file 'copyright.txt' in the top level directory for details.
5
6#pragma once
7
8// includes, FEAT
9#include <kernel/util/type_traits.hpp>
10#include <kernel/util/half.hpp>
11
12// includes, system
13#include <cmath>
14#include <limits>
15
16#if defined(FEAT_HAVE_QUADMATH) && !defined(__CUDACC__)
17extern "C"
18{
19# include <quadmath.h>
20}
21# define CAT_(x,y) x##y
22# define CAT(x,y) CAT_(x,y)
23# define WRAP_QUAD_MATH1(func) \
24 inline __float128 func(__float128 x) {return ::CAT(func,q)(x);}
25# define WRAP_QUAD_MATH2(func) \
26 inline __float128 func(__float128 x, __float128 y) {return ::CAT(func,q)(x, y);}
27# define WRAP_QUAD_MATH2PTR(func) \
28 inline __float128 func(__float128 x, __float128* y) {return ::CAT(func,q)(x, y);}
29#else
30# define WRAP_QUAD_MATH1(func)
31# define WRAP_QUAD_MATH2(func)
32# define WRAP_QUAD_MATH2PTR(func)
33#endif // FEAT_HAVE_QUADMATH && !__CUDA_CC__
34
35 // single argument function wrapper
36#define WRAP_STD_MATH1(func) \
37 inline float func(float x) {return std::func(x);} \
38 inline double func(double x) {return std::func(x);} \
39 inline long double func(long double x) {return std::func(x);}
40
41 // double argument function wrapper
42#define WRAP_STD_MATH2(func) \
43 inline float func(float x, float y) {return std::func(x,y);} \
44 inline double func(double x, double y) {return std::func(x,y);} \
45 inline long double func(long double x, long double y) {return std::func(x,y);}
46
47 // double argument function wrapper, second argument is pointer
48#define WRAP_STD_MATH2PTR(func) \
49 inline float func(float x, float* y) {return std::func(x,y);} \
50 inline double func(double x, double* y) {return std::func(x,y);} \
51 inline long double func(long double x, long double* y) {return std::func(x,y);}
52
53#define WRAP_STD_MATH2PTR_NO_CONSTEXPR(func) \
54 inline float func(float x, float* y) {return std::func(x,y);} \
55 inline double func(double x, double* y) {return std::func(x,y);} \
56 inline long double func(long double x, long double* y) {return std::func(x,y);}
57
58 // single argument function wrapper, bool return type
59#define WRAP_STD_MATH1BRET(func) \
60 inline bool func(float x) {return std::func(x);} \
61 inline bool func(double x) {return std::func(x);} \
62 inline bool func(long double x) {return std::func(x);}
63
64namespace FEAT
65{
72 namespace Math
73 {
74 // include C++ overloads of C89 math functions
75 WRAP_STD_MATH1(ceil)
76 WRAP_STD_MATH1(floor)
77 WRAP_STD_MATH2(fmod)
78 WRAP_STD_MATH2PTR(modf)
79
80 // wrap quadmath functions
81 WRAP_QUAD_MATH1(ceil)
82 WRAP_QUAD_MATH1(floor)
83 WRAP_QUAD_MATH2(fmod)
84 WRAP_QUAD_MATH2PTR(modf)
85
86
94 template<typename T_>
95 inline T_ sqr(T_ x)
96 {
97 return x * x;
98 }
99
108 template<typename T_>
109 inline T_ cub(T_ x)
110 {
111 return x * x * x;
112 }
113
122 template<typename T_>
123 inline T_ min(T_ a, T_ b)
124 {
125 return (a < b ? a : b);
126 }
127
136 template<typename T_>
137 inline T_ max(T_ a, T_ b)
138 {
139 return (a < b ? b : a);
140 }
141
153 template<typename T_>
154 inline void mini(T_& xmin, T_ x)
155 {
156 if(x < xmin)
157 xmin = x;
158 }
159
171 template<typename T_>
172 inline void maxi(T_& xmax, T_ x)
173 {
174 if(xmax < x)
175 xmax = x;
176 }
177
194 template<typename T_>
195 inline void minimax(T_ x, T_& a, T_& b)
196 {
197 if(x < a)
198 a = x;
199 if(b < x)
200 b = x;
201 }
202
215 template<typename T_>
216 inline T_ clamp(T_ x, T_ a, T_ b)
217 {
218 return max(a, min(x, b));
219 }
220
230 template<typename T_>
231 inline T_ ilog10(T_ x)
232 {
233 static_assert(Type::Traits<T_>::is_int, "ilog10 can only be applied to integral types");
234 T_ i(0);
235 while(x != T_(0))
236 {
237 ++i;
238 x /= T_(10);
239 }
240 return i;
241 }
242
249 template<typename T_>
250 inline T_ signum(T_ x)
251 {
252 return (x < T_(0) ? T_(-1) : (x > T_(0) ? T_(1) : T_(0)));
253 }
254
261 template<typename T_>
262 inline bool signbit(T_ x)
263 {
264 return x < T_(0);
265 }
266
274 template<typename T_>
275 inline T_ abs(T_ x)
276 {
277 return (x < T_(0.) ? -x : x);
278 }
279
280 // wrap std::abs
281 WRAP_STD_MATH1(abs)
282#if defined(FEAT_HAVE_QUADMATH) && !defined(__CUDACC__)
283 inline __float128 abs(__float128 x) {return ::fabsq(x);}
284#endif // FEAT_HAVE_QUADMATH && !__CUDA_CC__
285
295#ifdef FEAT_COMPILER_MICROSOFT
296#pragma warning(push)
297#pragma warning(disable:4723)
298#endif
299 template<typename T_>
300 inline T_ sqrt(T_ x)
301 {
302 static_assert(Type::Traits<T_>::is_float, "sqrt can only be applied to floating point types");
303
304 if(x <= T_(0))
305 return T_(0);
306
307 // use Newton iteration: y_{k+1} := y_k/2 * (3 - (y_k^2)/x)
308 // we choose y_0 = min(1,x); this ensures that the sequence y_k is monotonically increasing
309 // if y_{k+1} is not greater than y_k, we return y_k
310 const T_ z = T_(1) / x;
311 T_ y(Math::min(T_(1), x));
312 T_ yn(y);
313 do
314 {
315 y = yn;
316 yn = T_(0.5)*y * (T_(3) - (y*y*z));
317 } while(yn > y);
318
319 return y;
320 }
321#ifdef FEAT_COMPILER_MICROSOFT
322#pragma warning(pop)
323#endif
324
325 #ifdef FEAT_HAVE_HALFMATH
326 inline Half sqrt(Half x)
327 {
328 return __float2half(sqrt(__half2float(x)));
329 }
330 #endif
331
332 // wrap std::sqrt
333 WRAP_STD_MATH1(sqrt)
334 WRAP_QUAD_MATH1(sqrt)
335
336
343 template<typename T_>
344 inline T_ sin(T_ x)
345 {
346 static_assert(Type::Traits<T_>::is_float, "sin can only be applied to floating point types");
347
348 // use the exponential sum formula:
349 // infty x^(2*n+1)
350 // sin(x) := sum (-1)^n -----------
351 // n=0 (2*n+1)!
352 T_ y(x), yl(x+T_(1)), z(x);
353 T_ fn(1.0);
354 int n(1);
355 do
356 {
357 // update 1/(2*n+1)!
358 fn /= T_(++n);
359 fn /= T_(++n);
360 yl = y;
361 y += T_(1 - int(n&2)) * (z *= x*x) * T_(fn);
362 } while(yl != y);
363
364 return y;
365 }
366
367 #ifdef FEAT_HAVE_HALFMATH
368 inline Half sin(Half x)
369 {
370 return __float2half(sin(__half2float(x)));
371 }
372 #endif
373
374 // wrap std::sin
375 WRAP_STD_MATH1(sin)
376 WRAP_QUAD_MATH1(sin)
377
378
385 template<typename T_>
386 inline T_ cos(T_ x)
387 {
388 static_assert(Type::Traits<T_>::is_float, "cos can only be applied to floating point types");
389
390 // use the exponential sum formula:
391 // infty x^(2*n)
392 // cos(x) := sum (-1)^n ---------
393 // n=0 (2*n)!
394 T_ y(T_(1)), yl(T_(0)), z(T_(1));
395 T_ fn(1.0);
396 int n(0);
397 do
398 {
399 // update 1/(2*n)!
400 fn /= T_(++n);
401 fn /= T_(++n);
402 yl = y;
403 y += T_(1 - int(n&2)) * (z *= x*x) * T_(fn);
404 } while(yl != y);
405
406 return y;
407 }
408
409 // wrap std::cos
410 WRAP_STD_MATH1(cos)
411 WRAP_QUAD_MATH1(cos)
412
413 #ifdef FEAT_HAVE_HALFMATH
414 inline Half cos(Half x)
415 {
416 return __float2half(cos(__half2float(x)));
417 }
418 #endif
419
427 template<typename T_>
428 inline T_ tan(T_ x)
429 {
430 static_assert(Type::Traits<T_>::is_float, "tan can only be applied to floating point types");
431
432 return sin(x) / cos(x);
433 }
434
435 // wrap std::tan
436 WRAP_STD_MATH1(tan)
437 WRAP_QUAD_MATH1(tan)
438
439
446 template<typename T_>
447 inline T_ sinh(T_ x)
448 {
449 static_assert(Type::Traits<T_>::is_float, "sinh can only be applied to floating point types");
450
451 // use the exponential sum formula:
452 // infty x^(2*n+1)
453 // sinh(x) := sum -----------
454 // n=0 (2*n+1)!
455 T_ y(x), yl(x+T_(1)), z(x);
456 T_ fn(1.0);
457 int n(1);
458 do
459 {
460 // update 1/(2*n+1)!
461 fn /= T_(++n);
462 fn /= T_(++n);
463 yl = y;
464 y += (z *= x*x) * T_(fn);
465 } while(yl != y);
466
467 return y;
468 }
469
470 // wrap std::sinh
471 WRAP_STD_MATH1(sinh)
472 WRAP_QUAD_MATH1(sinh)
473
474 #ifdef FEAT_HAVE_HALFMATH
475 inline Half sinh(Half x)
476 {
477 return __float2half(sinh(__half2float(x)));
478 }
479 #endif
480
488 template<typename T_>
489 inline T_ cosh(T_ x)
490 {
491 static_assert(Type::Traits<T_>::is_float, "cosh can only be applied to floating point types");
492
493 // use the exponential sum formula:
494 // infty x^(2*n)
495 // cosh(x) := sum ---------
496 // n=0 (2*n)!
497 T_ y(T_(1)), yl(T_(0)), z(T_(1));
498 T_ fn(1.0);
499 int n(0);
500 do
501 {
502 // update 1/(2*n)!
503 fn /= T_(++n);
504 fn /= T_(++n);
505 yl = y;
506 y += (z *= x*x) * T_(fn);
507 } while(yl != y);
508
509 return y;
510 }
511
512 // wrap std::cosh
513 WRAP_STD_MATH1(cosh)
514 WRAP_QUAD_MATH1(cosh)
515
516 #ifdef FEAT_HAVE_HALFMATH
517 inline Half cosh(Half x)
518 {
519 return __float2half(cosh(__half2float(x)));
520 }
521 #endif
522
530 template<typename T_>
531 inline T_ tanh(T_ x)
532 {
533 static_assert(Type::Traits<T_>::is_float, "tanh can only be applied to floating point types");
534
535 return sinh(x) / cosh(x);
536 }
537
538 // wrap std::tanh
539 WRAP_STD_MATH1(tanh)
540 WRAP_QUAD_MATH1(tanh)
541
542
549 template<typename T_>
550 inline T_ exp(T_ x)
551 {
552 static_assert(Type::Traits<T_>::is_float, "exp can only be applied to floating point types");
553
554 T_ y(T_(1)), yl(T_(0)), z(y);
555 int n(0);
556 do
557 {
558 yl = y;
559 y += ((z *= x) /= T_(++n));
560 // Note about the stopping criterion:
561 // For x > 0, the sequence y_k must be strictly increasing.
562 // For x < 0, the sequence y_k must be alternating.
563 // And encode this into the most beautiful crypto-expression C++ has to offer ^_^
564 } while(x > T_(0) ? yl < y : n & 1 ? y < yl : yl < y);
565 return yl;
566 }
567
568 // wrap std::exp
569 WRAP_STD_MATH1(exp)
570 WRAP_QUAD_MATH1(exp)
571
572
579 template<typename T_>
580 inline T_ log(T_ x)
581 {
582 static_assert(Type::Traits<T_>::is_float, "log can only be applied to floating point types");
583
584 // use Newton iteration: y_{k+1} = y_k + 2*(x - exp(y_k))/(x + exp(y_k))
585 T_ y(T_(0)), yl(T_(0));
586 do
587 {
588 yl = y;
589 T_ ey(Math::exp(y));
590 y += T_(2) * (x - ey) / (x + ey);
591 // Note about the stopping criterion:
592 // For x > 1, the sequence y_k must be strictly increasing.
593 // For x < 1, the sequence y_k must be strictly decreasing.
594 // Again, encode this into one beautiful expression
595 } while(x < T_(1) ? y < yl : yl < y);
596 return yl;
597 }
598
599 // wrap std::log
600 WRAP_STD_MATH1(log)
601 WRAP_QUAD_MATH1(log)
602
603 #ifdef FEAT_HAVE_HALFMATH
604 inline Half exp(Half x)
605 {
606 return __float2half(exp(__half2float(x)));
607 }
608
609 inline Half log(Half x)
610 {
611 return __float2half(log(__half2float(x)));
612 }
613 #endif
614
622 template<typename T_>
623 inline T_ log10(T_ x)
624 {
625 static_assert(Type::Traits<T_>::is_float, "log10 can only be applied to floating point types");
626
627 return log(x) / log(T_(10));
628 }
629
630 // wrap std::log10
631 WRAP_STD_MATH1(log10)
632 WRAP_QUAD_MATH1(log10)
633
634
642 template<typename T_>
643 inline T_ pow(T_ x, T_ y)
644 {
645 static_assert(Type::Traits<T_>::is_float, "pow can only be applied to floating point types");
646
647 return Math::exp(y * Math::log(x));
648 }
649
650 // wrap std::pow
651 WRAP_STD_MATH2(pow)
652 WRAP_QUAD_MATH2(pow)
653
654
661 template<typename T_>
662 inline T_ atan(T_ x)
663 {
664 static_assert(Type::Traits<T_>::is_float, "atan can only be applied to floating point types");
665
666 // the exponential sum converges only for |x| < 1, but we can reduce any |x| >= 1 by
667 // atan(x) = 2*atan( x / (1 + sqrt(1 + x^2)))
668 int k(0);
669 for(; Math::abs(x) >= T_(1); ++k)
670 x /= (T_(1) + Math::sqrt(T_(1) + x*x));
671
672 // use the exponential sum formula:
673 // infty x^(2*n+1)
674 // atan(x) := sum (-1)^n -----------
675 // n=0 (2*n+1)
676 T_ y(x), yl(x+T_(1)), z(x);
677 int n(1);
678 do
679 {
680 yl = y;
681 T_ t((z *= x*x) / T_(n += 2));
682 y += T_(1 - int(n&2)) * t;
683 } while(yl != y);
684
685 return T_(1<<k) * y;
686 }
687
688 // wrap std::atan
689 WRAP_STD_MATH1(atan)
690 WRAP_QUAD_MATH1(atan)
691
692 #ifdef FEAT_HAVE_HALFMATH
693 inline Half atan(Half x)
694 {
695 return __float2half(atan(__half2float(x)));
696 }
697 #endif
698
707 template<typename T_>
708 inline T_ atan2(T_ y, T_ x)
709 {
710 static_assert(Type::Traits<T_>::is_float, "atan2 can only be applied to floating point types");
711
712 // see http://en.wikipedia.org/wiki/Atan2#Variations_and_notation
713 return T_(2) * atan((Math::sqrt(x*x + y*y) - x) / y);
714 }
715
716 // wrap std::atan2
717 WRAP_STD_MATH2(atan2)
718 WRAP_QUAD_MATH2(atan2)
719
720
723 template<typename T_>
724 inline T_ pi()
725 {
726 static_assert(Type::Traits<T_>::is_float, "pi can only be applied to floating point types");
727
728 // use the Bailey-Borwein-Plouffe formula:
729 // infty 1 ( 4 2 1 1 )
730 // pi := sum ---- * ( ---- - ---- - ---- - ---- )
731 // k=0 16^k ( 8k+1 8k+4 8k+5 8k+6 )
732 T_ y(T_(0)), yl(T_(0));
733 int k(0);
734 const T_ z(T_(1) / T_(16));
735 T_ t(T_(1));
736 do
737 {
738 yl = y;
739 y += t * (T_(4)/T_(8*k+1) - T_(2)/T_(8*k+4) - T_(1)/T_(8*k+5) - T_(1)/T_(8*k+6));
740 t *= z;
741 ++k;
742 } while(yl != y);
743
744 return y;
745 }
746
748 template<>
749 inline float pi<float>()
750 {
751 return 3.141592654f;
752 }
753
754 template<>
755 inline double pi<double>()
756 {
757 return 3.1415926535897932385;
758 }
759
760 template<>
761 inline long double pi<long double>()
762 {
763 return 3.141592653589793238462643383279502884197l;
764 }
765
766#ifdef FEAT_HAVE_QUADMATH
767 template<>
768 inline __float128 pi<__float128>()
769 {
770 return 3.141592653589793238462643383279502884197q;
771 }
772#endif
773
774 #ifdef FEAT_HAVE_HALFMATH
775 template<>
776 inline Half pi<Half>()
777 {
778 return __float2half(3.141592654f);
779 }
780 #endif
782
786 template<typename T_>
787 inline T_ eps()
788 {
789 static_assert(Type::Traits<T_>::is_float, "eps can only be applied to floating point types");
790
791 const T_ z(T_(1));
792 const T_ t(T_(0.5));
793 T_ y(t), yl(t);
794 do
795 {
796 yl = y;
797 y *= t;
798 } while(z < T_(z+y));
799 return yl;
800 }
801
803 template<>
804 inline float eps<float>()
805 {
806 return std::numeric_limits<float>::epsilon();
807 }
808 template<>
809 inline double eps<double>()
810 {
811 return std::numeric_limits<double>::epsilon();
812 }
813 template<>
814 inline long double eps<long double>()
815 {
816 return std::numeric_limits<long double>::epsilon();
817 }
818
819#if defined(FEAT_HAVE_QUADMATH) && !defined(__CUDACC__)
820 template<>
821 inline __float128 eps<__float128>()
822 {
823 return FLT128_EPSILON;
824 }
825#endif // FEAT_HAVE_QUADMATH && !__CUDA_CC__
826
827 #ifdef FEAT_HAVE_HALFMATH
828 template<>
829 inline Half eps<Half>()
830 {
831 return CUDART_ONE_FP16 - Half(0.99951171);
832 }
833 #endif
835
841 template<typename T_>
842 inline T_ huge()
843 {
844 return std::numeric_limits<T_>::max();
845 }
846
852 template<typename T_>
853 inline T_ tiny()
854 {
855 return std::numeric_limits<T_>::min();
856 }
857
859#if defined(FEAT_HAVE_QUADMATH) && !defined(__CUDACC__)
860 template<>
861 inline __float128 huge<__float128>()
862 {
863 return FLT128_MAX;
864 }
865
866 template<>
867 inline __float128 tiny<__float128>()
868 {
869 return FLT128_MIN;
870 }
871#endif // FEAT_HAVE_QUADMATH && !__CUDA_CC__
872
873 #ifdef FEAT_HAVE_HALFMATH
874 template<>
875 inline Half huge<Half>()
876 {
877 return CUDART_MAX_NORMAL_FP16;
878 }
879
880 template<>
881 inline Half tiny<Half>()
882 {
883 return CUDART_MIN_DENORM_FP16;
884 }
885 #endif
887
896 template<typename T_>
897 inline T_ nan()
898 {
899 // divide 0 by 0, which hopefully yields NaN
900 return T_(0) / T_(0);
901 }
902
904 template<>
905 inline float nan<float>()
906 {
907 return std::nanf("");
908 }
909
910 template<>
911 inline double nan<double>()
912 {
913 return std::nan("");
914 }
915
916 template<>
917 inline long double nan<long double>()
918 {
919 return std::nanl("");
920 }
921
922#if defined(FEAT_HAVE_QUADMATH) && !defined(__CUDACC__)
923 template<>
924 inline __float128 nan<__float128>()
925 {
926 return ::nanq("");
927 }
928#endif // FEAT_HAVE_QUADMATH && !__CUDA_CC__
929
930#if defined(FEAT_HAVE_FLOATX) && !defined(__CUDACC__)
931 /*template<int exp_bits_, int sig_bits_, typename Backend_>
932 inline flx::floatx<exp_bits_, sig_bits_, Backend_> nan<flx::floatx<exp_bits_, sig_bits_, Backend_>>()
933 {
934 // FloatX doesn't offer its own nan implementation,
935 // so create a backend type NaN and convert it to FloatX
936 return flx::floatx<exp_bits_, sig_bits_, Backend_>(Math::nan<Backend_>());
937 }*/
938#endif // FEAT_HAVE_FLOATX && !__CUDA_CC__
940
948 template<typename T_>
949 inline T_ asin(T_ x)
950 {
951 static_assert(Type::Traits<T_>::is_float, "asin can only be applied to floating point types");
952
953 return signum(x) * Math::atan(Math::sqrt((x*x) / (T_(1) - x*x)));
954 }
955
956 WRAP_STD_MATH1(asin)
957 WRAP_QUAD_MATH1(asin)
958
959
966 template<typename T_>
967 inline T_ acos(T_ x)
968 {
969 static_assert(Type::Traits<T_>::is_float, "acos can only be applied to floating point types");
970
971 return T_(0.5) * pi<T_>() - Math::asin(x);
972 }
973
974 WRAP_STD_MATH1(acos)
975 WRAP_QUAD_MATH1(acos)
976
977
988 template<typename T_>
989 inline bool isfinite(T_ x);
990
991 WRAP_STD_MATH1BRET(isfinite)
992
993#if defined(FEAT_HAVE_QUADMATH) && !defined(__CUDACC__)
994 inline bool isfinite(__float128 x)
995 {
996 // https://chromium.googlesource.com/native_client/nacl-gcc/+/ng/master/libquadmath/math/finiteq.c
997 return (::finiteq(x) != 0);
998 }
999#endif // FEAT_HAVE_QUADMATH && !__CUDA_CC__
1000
1001#if defined(FEAT_HAVE_FLOATX) && !defined(__CUDACC__)
1002 template<int exp_bits_, int sig_bits_, typename Backend_>
1003 inline bool isfinite(const flx::floatx<exp_bits_, sig_bits_, Backend_>& x)
1004 {
1005 // FloatX doesn't offer its own isfinite implementation,
1006 // so test its backend implementation instead
1007 return isfinite(static_cast<Backend_>(x));
1008 }
1009#endif // FEAT_HAVE_FLOATX && !__CUDA_CC__
1010
1011#ifdef FEAT_HAVE_HALFMATH
1012 inline bool isfinite(Half x)
1013 {
1014 return !(__hisinf(x) || __hisnan(x));
1015 }
1016#endif
1017
1027 template<typename T_>
1028 inline bool isinf(T_ x);
1029
1030 WRAP_STD_MATH1BRET(isinf)
1031
1032#if defined(FEAT_HAVE_QUADMATH) && !defined(__CUDACC__)
1033 inline bool isinf(__float128 x)
1034 {
1035 // https://chromium.googlesource.com/native_client/nacl-gcc/+/ng/master/libquadmath/math/isinfq.c
1036 return (::isinfq(x) != 0);
1037 }
1038#endif // FEAT_HAVE_QUADMATH && !__CUDA_CC__
1039
1040#if defined(FEAT_HAVE_FLOATX) && !defined(__CUDACC__)
1041 template<int exp_bits_, int sig_bits_, typename Backend_>
1042 inline bool isinf(const flx::floatx<exp_bits_, sig_bits_, Backend_>& x)
1043 {
1044 // FloatX doesn't offer its own isinf implementation,
1045 // so test its backend implementation instead
1046 return isinf(static_cast<Backend_>(x));
1047 }
1048#endif // FEAT_HAVE_FLOATX && !__CUDA_CC__
1049
1050#ifdef FEAT_HAVE_HALFMATH
1051 inline bool isinf(Half x)
1052 {
1053 return __hisinf(x);
1054 }
1055#endif
1056
1066 template<typename T_>
1067 inline bool isnan(T_ x);
1068
1069 WRAP_STD_MATH1BRET(isnan)
1070
1071#if defined(FEAT_HAVE_QUADMATH) && !defined(__CUDACC__)
1072 inline bool isnan(__float128 x)
1073 {
1074 // https://chromium.googlesource.com/native_client/nacl-gcc/+/ng/master/libquadmath/math/isnanq.c
1075 return (::isnanq(x) != 0);
1076 }
1077#endif // FEAT_HAVE_QUADMATH && !__CUDA_CC__
1078
1079#if defined(FEAT_HAVE_FLOATX) && !defined(__CUDACC__)
1080 template<int exp_bits_, int sig_bits_, typename Backend_>
1081 inline bool isnan(const flx::floatx<exp_bits_, sig_bits_, Backend_>& x)
1082 {
1083 // FloatX doesn't offer its own isnan implementation,
1084 // so test its backend implementation instead
1085 return isnan(static_cast<Backend_>(x));
1086 }
1087#endif // FEAT_HAVE_FLOATX && !__CUDA_CC__
1088
1089 #ifdef FEAT_HAVE_HALFMATH
1090 inline bool isnan(Half x)
1091 {
1092 return __hisnan(x);
1093 }
1094 #endif
1095
1107 template<typename T_>
1108 inline bool isnormal(T_ x);
1109
1110 WRAP_STD_MATH1BRET(isnormal)
1111
1112#if defined(FEAT_HAVE_QUADMATH) && !defined(__CUDACC__)
1113 inline bool isnormal(__float128 x)
1114 {
1115 // check whether the value is finite
1116 if(::finiteq(x) == 0)
1117 return false;
1118 // check whether the value is not below minimal normal value
1119 return !(::fabsq(x) < FLT128_MIN);
1120 }
1121#endif // FEAT_HAVE_QUADMATH && !__CUDA_CC__
1122
1123#if defined(FEAT_HAVE_FLOATX) && !defined(__CUDACC__)
1124 template<int exp_bits_, int sig_bits_, typename Backend_>
1125 inline bool isnormal(const flx::floatx<exp_bits_, sig_bits_, Backend_>& x)
1126 {
1127 // FloatX doesn't offer its own isnormal implementation,
1128 // so test its backend implementation instead
1129 return isnormal(static_cast<Backend_>(x));
1130 }
1131#endif // FEAT_HAVE_FLOATX && !__CUDA_CC__
1132
1133#ifdef FEAT_HAVE_HALFMATH
1134 inline bool isnormal(Half x)
1135 {
1136 return ((__hisinf(x) || __hisnan(x)) && (__habs(x) >= CUDART_MIN_DENORM_FP16));
1137 }
1138#endif
1139
1163 template<typename T_>
1164 inline T_ factorial(T_ n, T_ m = T_(0))
1165 {
1166 static_assert(Type::Traits<T_>::is_int, "factorial can only be applied to integral types");
1167
1168 // calculate the factorial
1169 T_ k(T_(1));
1170 for(m = max(T_(1), m); m <= n; ++m)
1171 {
1172 k *= m;
1173 }
1174 return k;
1175 }
1176
1195 template<typename T_>
1196 inline T_ binomial(T_ n, T_ k)
1197 {
1198 static_assert(Type::Traits<T_>::is_int, "binomial can only be applied to integral types");
1199
1200 if(k > n)
1201 {
1202 return T_(0); // by definition
1203 }
1204 else if((k <= T_(0)) || (k == n))
1205 {
1206 return T_(1); // by definition
1207 }
1208
1209 // exploit symmetry: (n \choose k) = (n \choose n-k)
1210 k = min(k, n-k);
1211
1212 // use multiplicative formula: (n \choose k+1) = (n - k) * (n \choose k) / (k + 1)
1213 T_ m = n;
1214 for(T_ i(1); i < k; ++i)
1215 {
1216 m *= (n - i);
1217 m /= (i + 1);
1218 }
1219
1220 return m;
1221 }
1222
1291 template<typename DT_, typename IT_>
1292 DT_ invert_matrix(const IT_ n, const IT_ stride, DT_ a[], IT_ p[])
1293 {
1294 // make sure that the parameters are valid
1295 if((n <= IT_(0)) || (stride < n) || (a == nullptr) || (p == nullptr))
1296 return DT_(0);
1297
1298 // invert 1x1 explicitly
1299 if(n == IT_(1))
1300 {
1301 DT_ det = a[0];
1302 a[0] = DT_(1) / det;
1303 return det;
1304 }
1305
1306 // initialize identity permutation
1307 for(IT_ i(0); i < n; ++i)
1308 {
1309 p[i] = i;
1310 }
1311
1312 // initialize determinant to 1
1313 DT_ det = DT_(1);
1314
1315 // primary column elimination loop
1316 for(IT_ k(0); k < n; ++k)
1317 {
1318 // step 1: find a pivot for the elimination of column k
1319 {
1320 // for this, we only check the rows p[j] with j >= k, as all
1321 // rows p[j] with j < k have already been eliminated and are
1322 // therefore not candidates for pivoting
1323 DT_ pivot = Math::abs(a[p[k]*stride + p[k]]);
1324 IT_ i = k;
1325
1326 // loop over all unprocessed rows
1327 for(IT_ j(k+1); j < n; ++j)
1328 {
1329 // get our matrix value and check whether it can be a pivot
1330 DT_ abs_val = Math::abs(a[p[j]*stride + p[j]]);
1331 if(abs_val > pivot)
1332 {
1333 pivot = abs_val;
1334 i = j;
1335 }
1336 }
1337
1338 // do we have to swap rows i and k?
1339 if(i > k)
1340 {
1341 // swap rows "virtually" by exchanging their permutation positions
1342 IT_ t = p[k];
1343 p[k] = p[i];
1344 p[i] = t;
1345 }
1346 }
1347
1348 // compute pivot row offset
1349 const IT_ pk_off = p[k]*stride;
1350
1351 // step 2: process pivot row
1352 {
1353 // update determinant by multiplying with the pivot element
1354 det *= a[pk_off + p[k]];
1355
1356 // get our inverted pivot element
1357 const DT_ pivot = DT_(1) / a[pk_off + p[k]];
1358
1359 // replace column entry by unit column entry
1360 a[pk_off + p[k]] = DT_(1);
1361
1362 // divide the whole row by the inverted pivot
1363 for(IT_ j(0); j < n; ++j)
1364 {
1365 a[pk_off+j] *= pivot;
1366 }
1367 }
1368
1369 // step 3: eliminate pivot column
1370
1371 // loop over all rows of the matrix
1372 for(IT_ i(0); i < n; ++i)
1373 {
1374 // skip the pivot row
1375 if(i == p[k])
1376 continue;
1377
1378 // compute row and pivot offsets
1379 const IT_ row_off = i*stride;
1380
1381 // fetch elimination factor
1382 const DT_ factor = a[row_off + p[k]];
1383
1384 // replace by unit column entry
1385 a[row_off + p[k]] = DT_(0);
1386
1387 // process the row
1388 for(IT_ j(0); j < n; ++j)
1389 {
1390 a[row_off + j] -= a[pk_off + j] * factor;
1391 }
1392 }
1393 }
1394
1395 // return determinant
1396 return det;
1397 }
1398
1413 template<typename DT_>
1414 DT_ calc_opening_angle_intern(DT_ cross_prod, DT_ dot_prod)
1415 {
1416 DT_ theta;
1417 // We always want to use the version that uses values nearer to 1 for better conditioning
1418 if(Math::abs(cross_prod) < DT_(0.5))
1419 {
1420 theta = Math::asin(cross_prod);
1421 // Transform to [0,2pi]
1422 if(theta >= DT_(0))
1423 theta = (dot_prod >= DT_(0)) ? theta : (Math::pi<DT_>() - theta);
1424 else
1425 theta = (dot_prod >= DT_(0)) ? (DT_(2) * Math::pi<DT_>() + theta) : (Math::pi<DT_>() - theta);
1426 }
1427 else
1428 {
1429 theta = Math::acos(dot_prod);
1430 //Transform to [0,2pi]
1431 theta = (cross_prod >= DT_(0)) ? theta : (DT_(2) * Math::pi<DT_>() - theta);
1432 }
1433 return theta;
1434 }
1435
1449 template<typename DT_>
1450 DT_ calc_opening_angle(DT_ x1, DT_ x2, DT_ y1, DT_ y2)
1451 {
1452 DT_ norm_x = Math::sqrt(Math::sqr(x1) + Math::sqr(x2));
1453 DT_ norm_y = Math::sqrt(Math::sqr(y1) + Math::sqr(y2));
1454 x1 /= norm_x;
1455 x2 /= norm_x;
1456 y1 /= norm_y;
1457 y2 /= norm_y;
1458
1459 DT_ cross = x1*y2 - y1*x2;
1460 DT_ dot = x1*y1 + x2*y2;
1461
1462 return calc_opening_angle_intern(cross, dot);
1463 }
1464
1465
1472 template<typename T_>
1473 class Limits :
1474 public std::numeric_limits<T_>
1475 {
1476 }; // class Limits<...>
1477
1478#if defined(FEAT_HAVE_QUADMATH) && !defined(__CUDACC__)
1479 template<>
1480 class Limits<__float128>
1481 {
1482 public:
1483 static constexpr bool is_specialized = true;
1484 static /*constexpr*/ __float128 min() noexcept { return FLT128_MIN; }
1485 static /*constexpr*/ __float128 max() noexcept { return FLT128_MAX; }
1486 static /*constexpr*/ __float128 lowest() noexcept { return -FLT128_MAX; }
1487 static constexpr int digits = FLT128_MANT_DIG;
1488 static constexpr int digits10 = FLT128_DIG;
1489 // Note: The following formula was taken from the MSC implementation...
1490 static constexpr int max_digits10 = (2 + FLT128_MANT_DIG * 301 / 1000);
1491 static constexpr bool is_signed = true;
1492 static constexpr bool is_integer = false;
1493 static constexpr bool is_exact = false;
1494 static constexpr int radix = 2;
1495 static /*constexpr*/ __float128 epsilon() noexcept { return FLT128_EPSILON; }
1496 static constexpr __float128 round_error() noexcept { return __float128(0.5); }
1497 static constexpr int min_exponent = FLT128_MIN_EXP;
1498 static constexpr int min_exponent10 = FLT128_MIN_10_EXP;
1499 static constexpr int max_exponent = FLT128_MAX_EXP;
1500 static constexpr int max_exponent10 = FLT128_MAX_10_EXP;
1501 static constexpr bool has_infinity = true;
1502 static constexpr bool has_quiet_NaN = true;
1503 static constexpr bool has_signaling_NaN = false;
1504 static constexpr std::float_denorm_style has_denorm = std::denorm_absent;
1505 static constexpr bool has_denorm_loss = false;
1506 static /*constexpr*/ __float128 infinity() noexcept { return max()*max(); }
1507 static /*constexpr*/ __float128 quiet_NaN() noexcept { return ::nanq(nullptr); }
1508 static /*constexpr*/ __float128 signaling_NaN() noexcept { return ::nanq(nullptr); }
1509 static /*constexpr*/ __float128 denorm_min() noexcept { return FLT128_DENORM_MIN; }
1510 static constexpr bool is_iec559 = false;
1511 static constexpr bool is_bounded = true;
1512 static constexpr bool is_modulo = false;
1513 static constexpr bool traps = true;
1514 static constexpr bool tinyness_before = true;
1515 static constexpr std::float_round_style round_style = std::round_to_nearest;
1516 };
1517#endif // FEAT_HAVE_QUADMATH && !__CUDA_CC__
1518 } // namespace Math
1519} // namespace FEAT
Math Limits class template.
Definition: math.hpp:1475
T_ sqrt(T_ x)
Returns the square-root of a value.
Definition: math.hpp:300
T_ sinh(T_ x)
Returns the hyperbolic sine of a value.
Definition: math.hpp:447
DT_ calc_opening_angle_intern(DT_ cross_prod, DT_ dot_prod)
Calculates the opening angle from the dot and cross product of two 2D vectors.
Definition: math.hpp:1414
T_ tiny()
Returns the minimum positive finite (full-precision) value for a data type.
Definition: math.hpp:853
T_ factorial(T_ n, T_ m=T_(0))
Calculates the (partial) factorial.
Definition: math.hpp:1164
T_ atan(T_ x)
Returns the arctangent of a value.
Definition: math.hpp:662
bool isinf(T_ x)
Checks whether a value is infinite.
T_ pi()
Returns the mathematical constant pi = 3.1415...
Definition: math.hpp:724
T_ atan2(T_ y, T_ x)
Returns the arctangent of y/x.
Definition: math.hpp:708
bool isnormal(T_ x)
Checks whether a value is normal.
T_ abs(T_ x)
Returns the absolute value.
Definition: math.hpp:275
T_ exp(T_ x)
Returns the exponential of a value.
Definition: math.hpp:550
T_ clamp(T_ x, T_ a, T_ b)
Clamps a value to a range.
Definition: math.hpp:216
void mini(T_ &xmin, T_ x)
Updates the minimum of a set of values.
Definition: math.hpp:154
T_ cosh(T_ x)
Returns the hyperbolic cosine of a value.
Definition: math.hpp:489
T_ tanh(T_ x)
Returns the hyperbolic tangent of a value.
Definition: math.hpp:531
T_ acos(T_ x)
Returns the arccosine of a value.
Definition: math.hpp:967
T_ nan()
Returns a quiet Not-A-Number (NaN)
Definition: math.hpp:897
DT_ calc_opening_angle(DT_ x1, DT_ x2, DT_ y1, DT_ y2)
Calculates the opening angle of two 2D vectors.
Definition: math.hpp:1450
T_ pow(T_ x, T_ y)
Returns x raised to the power of y.
Definition: math.hpp:643
T_ asin(T_ x)
Returns the arcsine of a value.
Definition: math.hpp:949
T_ binomial(T_ n, T_ k)
Calculates the binomial coefficient.
Definition: math.hpp:1196
void minimax(T_ x, T_ &a, T_ &b)
Updates the minimum and maximum.
Definition: math.hpp:195
T_ sin(T_ x)
Returns the sine of a value.
Definition: math.hpp:344
T_ sqr(T_ x)
Returns the square of a value.
Definition: math.hpp:95
void maxi(T_ &xmax, T_ x)
Updates the maximum of a set of values.
Definition: math.hpp:172
T_ min(T_ a, T_ b)
Returns the minimum of two values.
Definition: math.hpp:123
T_ cub(T_ x)
Returns the cube of a value.
Definition: math.hpp:109
T_ huge()
Returns the maximum positive finite (full-precision) value for a data type.
Definition: math.hpp:842
T_ tan(T_ x)
Returns the tangent of a value.
Definition: math.hpp:428
DT_ invert_matrix(const IT_ n, const IT_ stride, DT_ a[], IT_ p[])
Inverts a matrix and returns its determinant.
Definition: math.hpp:1292
T_ signum(T_ x)
Returns the sign of a value.
Definition: math.hpp:250
T_ log10(T_ x)
Returns the logarithm to the base 10 of a value.
Definition: math.hpp:623
bool signbit(T_ x)
Returns the status of the sign bit.
Definition: math.hpp:262
T_ ilog10(T_ x)
Computes the integral base-10 logarithm of an integer, i.e. its number of non-zero decimal digits.
Definition: math.hpp:231
bool isfinite(T_ x)
Checks whether a value is finite.
bool isnan(T_ x)
Checks whether a value is Not-A-Number.
T_ cos(T_ x)
Returns the cosine of a value.
Definition: math.hpp:386
T_ log(T_ x)
Returns the natural logarithm of a value.
Definition: math.hpp:580
T_ max(T_ a, T_ b)
Returns the maximum of two values.
Definition: math.hpp:137
T_ eps()
Returns the machine precision constant for a floating-point data type.
Definition: math.hpp:787
FEAT namespace.
Definition: adjactor.hpp:12
__half Half
Half data type.
Definition: half.hpp:25
basic Type Traits struct
Definition: type_traits.hpp:73