/*************************************************************************** Math.h - description ------------------- begin : 2005/07/05 copyright : (C) 2005 by Tomas Oberhuber email : tomas.oberhuber@fjfi.cvut.cz ***************************************************************************/ /* See Copyright Notice in tnl/Copyright */ #pragma once #include <cmath> #include <type_traits> #include <algorithm> #include <TNL/Devices/CudaCallable.h> namespace TNL { template< typename T1, typename T2 > using enable_if_same_base = std::enable_if< std::is_same< typename std::decay< T1 >::type, T2 >::value, T2 >; template< typename T1, typename T2 > using both_integral_or_floating = typename std::conditional< ( std::is_integral< T1 >::value && std::is_integral< T2 >::value ) || ( std::is_floating_point< T1 >::value && std::is_floating_point< T2 >::value ), std::true_type, std::false_type >::type; // 1. If both types are integral or floating-point, the larger type is selected. // 2. If one type is integral and the other floating-point, the floating-point type is selected. // Casting both arguments to the same type is necessary because std::min and std::max // are implemented as a single-type template. template< typename T1, typename T2 > using larger_type = typename std::conditional< ( both_integral_or_floating< T1, T2 >::value && sizeof(T1) >= sizeof(T2) ) || std::is_floating_point<T1>::value, T1, T2 >::type; /*** * This function returns minimum of two numbers. * GPU device code uses the functions defined in the CUDA's math_functions.h, * MIC uses trivial override and host uses the STL functions. */ template< typename T1, typename T2, typename ResultType = larger_type< T1, T2 > > __cuda_callable__ inline ResultType min( const T1& a, const T2& b ) { #if defined(__CUDA_ARCH__) return ::min( (ResultType) a, (ResultType) b ); #elif defined(__MIC__) return a < b ? a : b; #else return std::min( (ResultType) a, (ResultType) b ); #endif } /*** * This function returns maximum of two numbers. * GPU device code uses the functions defined in the CUDA's math_functions.h, * MIC uses trivial override and host uses the STL functions. */ template< typename T1, typename T2, typename ResultType = larger_type< T1, T2 > > __cuda_callable__ ResultType max( const T1& a, const T2& b ) { #if defined(__CUDA_ARCH__) return ::max( (ResultType) a, (ResultType) b ); #elif defined(__MIC__) return a > b ? a : b; #else return std::max( (ResultType) a, (ResultType) b ); #endif } /*** * This function returns absolute value of given number. */ template< class T > __cuda_callable__ inline T abs( const T& n ) { #if defined(__MIC__) if( n < ( T ) 0 ) return -n; return n; #else return std::abs( n ); #endif } /*** * This function returns argument of minimum of two numbers. */ template< typename T1, typename T2, typename ResultType = larger_type< T1, T2 > > __cuda_callable__ inline ResultType argMin( const T1& a, const T2& b ) { return ( a < b ) ? a : b; } /*** * This function returns argument of maximum of two numbers. */ template< typename T1, typename T2, typename ResultType = larger_type< T1, T2 > > __cuda_callable__ ResultType argMax( const T1& a, const T2& b ) { return ( a > b ) ? a : b; } /*** * This function returns argument of minimum of absolute values of two numbers. */ template< typename T1, typename T2, typename ResultType = larger_type< T1, T2 > > __cuda_callable__ inline ResultType argAbsMin( const T1& a, const T2& b ) { return ( TNL::abs( a ) < TNL::abs( b ) ) ? a : b; } /*** * This function returns argument of maximum of absolute values of two numbers. */ template< typename T1, typename T2, typename ResultType = larger_type< T1, T2 > > __cuda_callable__ ResultType argAbsMax( const T1& a, const T2& b ) { return ( TNL::abs( a ) > TNL::abs( b ) ) ? a : b; } template< typename T1, typename T2, typename ResultType = larger_type< T1, T2 > > __cuda_callable__ inline ResultType pow( const T1& base, const T2& exp ) { #if defined(__CUDA_ARCH__) || defined(__MIC__) return ::pow( (ResultType) base, (ResultType) exp ); #else return std::pow( (ResultType) base, (ResultType) exp ); #endif } template< typename T > __cuda_callable__ inline T sqrt( const T& value ) { #if defined(__CUDA_ARCH__) || defined(__MIC__) return ::sqrt( value ); #else return std::sqrt( value ); #endif } template< typename Type > __cuda_callable__ void swap( Type& a, Type& b ) { Type tmp( a ); a = b; b = tmp; } template< class T > __cuda_callable__ T sign( const T& a ) { if( a < ( T ) 0 ) return ( T ) -1; if( a == ( T ) 0 ) return ( T ) 0; return ( T ) 1; } template< typename Real > __cuda_callable__ bool isSmall( const Real& v, const Real& tolerance = 1.0e-5 ) { return ( -tolerance <= v && v <= tolerance ); } __cuda_callable__ inline int roundUpDivision( const int num, const int div ) { return num / div + ( num % div != 0 ); } __cuda_callable__ inline int roundToMultiple( int number, int multiple ) { return multiple*( number/ multiple + ( number % multiple != 0 ) ); } __cuda_callable__ inline bool isPow2( int x ) { return ( ( x & ( x - 1 ) ) == 0 ); } __cuda_callable__ inline bool isPow2( long int x ) { return ( ( x & ( x - 1 ) ) == 0 ); } } // namespace TNL