// ____ ______ __ // / __ \ / ____// / // / /_/ // / / / // / ____// /___ / /___ PixInsight Class Library // /_/ \____//_____/ PCL 2.4.23 // ---------------------------------------------------------------------------- // pcl/Math.h - Released 2022-03-12T18:59:29Z // ---------------------------------------------------------------------------- // This file is part of the PixInsight Class Library (PCL). // PCL is a multiplatform C++ framework for development of PixInsight modules. // // Copyright (c) 2003-2022 Pleiades Astrophoto S.L. All Rights Reserved. // // Redistribution and use in both source and binary forms, with or without // modification, is permitted provided that the following conditions are met: // // 1. All redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // 2. All redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. Neither the names "PixInsight" and "Pleiades Astrophoto", nor the names // of their contributors, may be used to endorse or promote products derived // from this software without specific prior written permission. For written // permission, please contact info@pixinsight.com. // // 4. All products derived from this software, in any form whatsoever, must // reproduce the following acknowledgment in the end-user documentation // and/or other materials provided with the product: // // "This product is based on software from the PixInsight project, developed // by Pleiades Astrophoto and its contributors (https://pixinsight.com/)." // // Alternatively, if that is where third-party acknowledgments normally // appear, this acknowledgment must be reproduced in the product itself. // // THIS SOFTWARE IS PROVIDED BY PLEIADES ASTROPHOTO AND ITS CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PLEIADES ASTROPHOTO OR ITS // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, BUSINESS // INTERRUPTION; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; AND LOSS OF USE, // DATA OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // ---------------------------------------------------------------------------- #ifndef __PCL_Math_h #define __PCL_Math_h /// \file pcl/Math.h #include #include #include #include #include #include #include #include #include #ifdef _MSC_VER # include // for __cpuid() #endif #if defined( __x86_64__ ) || defined( _M_X64 ) || defined( __PCL_MACOSX ) # define __PCL_HAVE_SSE2 1 # include #endif /* * sincos() is only available as a GNU extension: * * http://man7.org/linux/man-pages/man3/sincos.3.html * * Unfortunately, it is not part of the C++ standard library because of the * anachronic dependency on errno. */ #if !defined( _MSC_VER ) && !defined( __clang__ ) && defined( __GNUC__ ) # define __PCL_HAVE_SINCOS 1 #endif #ifdef __PCL_QT_INTERFACE # include #endif /* * Number of histogram bins used by fast histogram-based median calculation * algorithm implementations. */ #define __PCL_MEDIAN_HISTOGRAM_LENGTH 8192 namespace pcl { // ---------------------------------------------------------------------------- /*! * \defgroup hw_identification_functions Hardware Identification Routines */ /*! * Returns an integer representing the highest set of Streaming SIMD Extensions * instructions (SSE) supported by the running processor. This function is a * portable wrapper to the CPUID x86 instruction. * * The returned value can be one of: * *
 *  0 : No SSE instructions supported
 *  1 : SSE instructions set supported
 *  2 : SSE2 instructions set supported
 *  3 : SSE3 instructions set supported
 * 41 : SSE4.1 instructions set supported
 * 42 : SSE4.2 instructions set supported
 * 
* * \ingroup hw_identification_functions */ inline int MaxSSEInstructionSetSupported() noexcept { int32 edxFlags = 0; int32 ecxFlags = 0; #ifdef _MSC_VER int cpuInfo[ 4 ]; __cpuid( cpuInfo, 1 ); edxFlags = cpuInfo[3]; ecxFlags = cpuInfo[2]; #else asm volatile( "mov $0x00000001, %%eax\n\t" "cpuid\n\t" "mov %%edx, %0\n\t" "mov %%ecx, %1\n" : "=r" (edxFlags), "=r" (ecxFlags) // output operands : // input operands : "%eax", "%ebx", "%ecx", "%edx" ); // clobbered registers #endif if ( ecxFlags & (1u << 20) ) // SSE4.2 return 42; if ( ecxFlags & (1u << 19) ) // SSE4.1 return 41; if ( ecxFlags & 1u ) // SSE3 return 3; if ( edxFlags & (1u << 26) ) // SSE2 return 2; if ( edxFlags & (1u << 25) ) // SSE return 1; return 0; } // ---------------------------------------------------------------------------- /*! * \defgroup fpclassification_functions Floating Point Number Classification */ #define __PCL_FLOAT_SGNMASK 0x80000000 #define __PCL_FLOAT_EXPMASK 0x7f800000 #define __PCL_FLOAT_SIGMASK 0x007fffff /*! * Returns true iff the specified 32-bit floating point number is \e finite. * A number is finite if it is neither NaN (Not a Number) nor positive or * negative infinity. * * \ingroup fpclassification_functions * \sa IsNaN( float ), IsInfinity( float ) */ inline bool IsFinite( float x ) noexcept { union { float f; uint32 u; } v = { x }; return (v.u & __PCL_FLOAT_EXPMASK) != __PCL_FLOAT_EXPMASK; } /*! * Returns true iff the specified 32-bit floating point number is \e NaN. A NaN * (Not A Number) is a special value in the IEEE 754 standard used to represent * an undefined or unrepresentable value, such as the result of invalid * operations like 0/0, or real operations with complex results as the square * root of a negative number. * * \ingroup fpclassification_functions * \sa IsFinite( float ), IsInfinity( float ) */ inline bool IsNaN( float x ) noexcept { union { float f; uint32 u; } v = { x }; return (v.u & __PCL_FLOAT_EXPMASK) == __PCL_FLOAT_EXPMASK && (v.u & __PCL_FLOAT_SIGMASK) != 0; } /*! * Returns a nonzero integer value if the specified 32-bit floating point * number is an \e infinity. * * This function returns: * *
 * +1 if \a x is positive infinity.
 * -1 if \a x is negative infinity.
 *  0 if \a x is either NaN or a finite value.
 * 
* * \ingroup fpclassification_functions * \sa IsFinite( float ), IsNaN( float ) */ inline int IsInfinity( float x ) noexcept { union { float f; uint32 u; } v = { x }; if ( (v.u & __PCL_FLOAT_EXPMASK) == __PCL_FLOAT_EXPMASK && (v.u & __PCL_FLOAT_SIGMASK) == 0 ) return ((v.u & __PCL_FLOAT_SGNMASK) == 0) ? +1 : -1; return 0; } /*! * Returns true iff the specified 32-bit floating point number is a negative * zero. * * \ingroup fpclassification_functions */ inline bool IsNegativeZero( float x ) noexcept { union { float f; uint32 u; } v = { x }; return v.u == __PCL_FLOAT_SGNMASK; } #define __PCL_DOUBLE_SGNMASK 0x80000000 #define __PCL_DOUBLE_EXPMASK 0x7ff00000 #define __PCL_DOUBLE_SIGMASK 0x000fffff /*! * Returns true iff the specified 64-bit floating point number is \e finite. * A number is finite if it is neither NaN (Not a Number) nor positive or * negative infinity. * * \ingroup fpclassification_functions * \sa IsNaN( double ), IsInfinity( double ) */ inline bool IsFinite( double x ) noexcept { union { double d; uint32 u[2]; } v = { x }; return (v.u[1] & __PCL_DOUBLE_EXPMASK) != __PCL_DOUBLE_EXPMASK; } /*! * Returns true iff the specified 64-bit floating point number is \e NaN. A NaN * (Not A Number) is a special value in the IEEE 754 standard used to represent * an undefined or unrepresentable value, such as the result of invalid * operations like 0/0, or real operations with complex results as the square * root of a negative number. * * \ingroup fpclassification_functions * \sa IsFinite( double ), IsInfinity( double ) */ inline bool IsNaN( double x ) noexcept { union { double d; uint32 u[2]; } v = { x }; return (v.u[1] & __PCL_DOUBLE_EXPMASK) == __PCL_DOUBLE_EXPMASK && (v.u[0] != 0 || (v.u[1] & __PCL_DOUBLE_SIGMASK) != 0); } /*! * Returns a nonzero integer value if the specified 64-bit floating point * number is an \e infinity. * * This function returns: * *
 * +1 if \a x is positive infinity.
 * -1 if \a x is negative infinity.
 *  0 if \a x is either NaN or a finite value.
 * 
* * \ingroup fpclassification_functions * \sa IsFinite( double ), IsNaN( double ) */ inline int IsInfinity( double x ) noexcept { union { double d; uint32 u[2]; } v = { x }; if ( v.u[0] == 0 && (v.u[1] & __PCL_DOUBLE_SIGMASK) == 0 && (v.u[1] & __PCL_DOUBLE_EXPMASK) == __PCL_DOUBLE_EXPMASK ) return ((v.u[1] & __PCL_DOUBLE_SGNMASK) == 0) ? +1 : -1; return 0; } /*! * Returns true iff the specified 64-bit floating point number is a negative * zero. * * \ingroup fpclassification_functions */ inline bool IsNegativeZero( double x ) noexcept { union { double d; uint32 u[2]; } v = { x }; return v.u[1] == __PCL_DOUBLE_SGNMASK && v.u[0] == 0; } // ---------------------------------------------------------------------------- /*! * \defgroup mathematical_functions Mathematical Functions */ /*! * Absolute value of \a x. * \ingroup mathematical_functions */ inline float Abs( float x ) noexcept { return std::fabs( x ); } /*! * \ingroup mathematical_functions */ inline double Abs( double x ) noexcept { return std::fabs( x ); } /*! * \ingroup mathematical_functions */ inline long double Abs( long double x ) noexcept { return std::fabs( x ); } /*! * \ingroup mathematical_functions */ inline signed int Abs( signed int x ) noexcept { return ::abs( x ); } /*! * \ingroup mathematical_functions */ #if defined( __PCL_MACOSX ) && defined( __clang__ ) // turn off warning due to broken cstdlib in Xcode _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wabsolute-value\"") #endif inline signed long Abs( signed long x ) noexcept { return ::abs( x ); } #if defined( __PCL_MACOSX ) && defined( __clang__ ) _Pragma("clang diagnostic pop") #endif /*! * \ingroup mathematical_functions */ #if defined( _MSC_VER ) inline __int64 Abs( __int64 x ) noexcept { return (x < 0) ? -x : +x; } #elif defined( __PCL_MACOSX ) && defined( __clang__ ) inline constexpr signed long long Abs( signed long long x ) noexcept { return (x < 0) ? -x : +x; } #else inline signed long long Abs( signed long long x ) noexcept { return ::abs( x ); } #endif /*! * \ingroup mathematical_functions */ inline signed short Abs( signed short x ) noexcept { return (signed short)::abs( int( x ) ); } /*! * \ingroup mathematical_functions */ inline signed char Abs( signed char x ) noexcept { return (signed char)::abs( int( x ) ); } /*! * \ingroup mathematical_functions */ inline wchar_t Abs( wchar_t x ) noexcept { return (wchar_t)::abs( int( x ) ); } /*! * \ingroup mathematical_functions */ inline constexpr unsigned int Abs( unsigned int x ) noexcept { return x; } /*! * \ingroup mathematical_functions */ inline constexpr unsigned long Abs( unsigned long x ) noexcept { return x; } /*! * \ingroup mathematical_functions */ #ifdef _MSC_VER inline unsigned __int64 Abs( unsigned __int64 x ) noexcept { return x; } #else inline constexpr unsigned long long Abs( unsigned long long x ) noexcept { return x; } #endif /*! * \ingroup mathematical_functions */ inline constexpr unsigned short Abs( unsigned short x ) noexcept { return x; } /*! * \ingroup mathematical_functions */ inline constexpr unsigned char Abs( unsigned char x ) noexcept { return x; } // ---------------------------------------------------------------------------- /*! * The pi constant: 3.141592... * \ingroup mathematical_functions */ inline constexpr long double Pi() noexcept { return (long double)( 0.31415926535897932384626433832795029e+01L ); } /*! * Twice the pi constant: 0.6283185... * \ingroup mathematical_functions */ inline constexpr long double TwoPi() noexcept { return (long double)( 0.62831853071795864769252867665590058e+01L ); } // ---------------------------------------------------------------------------- /*! * Merges a complex angle given by degrees and arcminutes into single degrees. * \ingroup mathematical_functions */ template inline constexpr T Angle( int d, T m ) noexcept { return d + m/60; } /*! * Merges a complex angle given by degrees, arcminutes and arcseconds into * single degrees. * \ingroup mathematical_functions */ template inline constexpr T Angle( int d, int m, T s ) noexcept { return Angle( d, m + s/60 ); } // ---------------------------------------------------------------------------- /*! * Inverse cosine function (arccosine). * \ingroup mathematical_functions */ template inline constexpr T ArcCos( T x ) noexcept { PCL_PRECONDITION( T( -1 ) <= x && x <= T( 1 ) ) return std::acos( x ); } // ---------------------------------------------------------------------------- /*! * Inverse sine function (arcsine). * \ingroup mathematical_functions */ template inline constexpr T ArcSin( T x ) noexcept { PCL_PRECONDITION( T( -1 ) <= x && x <= T( 1 ) ) return std::asin( x ); } // ---------------------------------------------------------------------------- /*! * Inverse tangent function (arctangent). * \ingroup mathematical_functions */ template inline constexpr T ArcTan( T x ) noexcept { return std::atan( x ); } // ---------------------------------------------------------------------------- /*! * Arctangent of y/x, result in the proper quadrant. * \ingroup mathematical_functions */ template inline constexpr T ArcTan( T y, T x ) noexcept { return std::atan2( y, x ); } // ---------------------------------------------------------------------------- /*! * Arctangent of y/x, proper quadrant, result in the interval [0,2pi). * \ingroup mathematical_functions */ template inline T ArcTan2Pi( T y, T x ) noexcept { T r = ArcTan( y, x ); if ( r < 0 ) r = static_cast( r + TwoPi() ); return r; } // ---------------------------------------------------------------------------- /*! * The ceil function: lowest integer >= x. * \ingroup mathematical_functions */ template inline constexpr T Ceil( T x ) noexcept { return std::ceil( x ); } // ---------------------------------------------------------------------------- /*! * Cosine function. * \ingroup mathematical_functions */ template inline constexpr T Cos( T x ) noexcept { return std::cos( x ); } // ---------------------------------------------------------------------------- /*! * Hyperbolic Cosine function. * \ingroup mathematical_functions */ template inline constexpr T Cosh( T x ) noexcept { return std::cosh( x ); } // ---------------------------------------------------------------------------- /*! * Cotangent of x, equal to Cos(x)/Sin(x) or 1/Tan(x). * \ingroup mathematical_functions */ template inline constexpr T Cotan( T x ) noexcept { return T( 1 )/std::tan( x ); } // ---------------------------------------------------------------------------- /*! * Conversion from radians to degrees. * \ingroup mathematical_functions */ template inline constexpr T Deg( T x ) noexcept { return static_cast( 0.572957795130823208767981548141051700441964e+02L * x ); } // ---------------------------------------------------------------------------- /*! * The exponential function e**x. * \ingroup mathematical_functions */ template inline constexpr T Exp( T x ) noexcept { return std::exp( x ); } // ---------------------------------------------------------------------------- /*! * The floor function: highest integer <= x. * \ingroup mathematical_functions */ template inline constexpr T Floor( T x ) noexcept { return std::floor( x ); } // ---------------------------------------------------------------------------- /*! * Fractional part of x. * The returned value is within (-1,+1), and has the same sign as x. * \ingroup mathematical_functions */ template inline constexpr T Frac( T x ) noexcept { return std::modf( x, &x ); } // ---------------------------------------------------------------------------- /*! * Calculates base-2 mantissa and exponent. * The arguments \a m and \a p receive the values of the base-2 mantissa and * exponent, respectively, such that: 0.5 <= m < 1.0, x = m * 2**p * \ingroup mathematical_functions */ template inline void Frexp( T x, T& m, int& p ) noexcept { m = std::frexp( x, &p ); } // ---------------------------------------------------------------------------- /*! * Haversine function: * * Hav( x ) = (1 - Cos( x ))/2 * * The haversine is useful to work with tiny angles. * * \ingroup mathematical_functions */ template inline constexpr T Hav( T x ) noexcept { return (1 - Cos( x ))/2; } // ---------------------------------------------------------------------------- /*! * Calculates m * 2**p. * \ingroup mathematical_functions */ template inline constexpr T Ldexp( T m, int p ) noexcept { return std::ldexp( m, p ); } // ---------------------------------------------------------------------------- /*! * Natural (base e) logarithm of \a x. * \ingroup mathematical_functions */ template inline constexpr T Ln( T x ) noexcept { PCL_PRECONDITION( x >= 0 ) return std::log( x ); } // ---------------------------------------------------------------------------- struct PCL_CLASS FactorialCache { constexpr static int s_cacheSize = 127; static const double s_lut[ s_cacheSize+1 ]; }; /*! * The factorial of \a n ≥ 0. * * A static lookup table is used to speed up for \a n <= 127. * * \ingroup mathematical_functions */ inline double Factorial( int n ) noexcept { PCL_PRECONDITION( n >= 0 ) if ( n <= FactorialCache::s_cacheSize ) return FactorialCache::s_lut[n]; double x = FactorialCache::s_lut[FactorialCache::s_cacheSize]; for ( int m = FactorialCache::s_cacheSize; ++m <= n; ) x *= m; return x; } /*! * The natural logarithm of the factorial of \a n ≥ 0. * * For \a n <= 127 computes the natural logarithm of the factorial function * directly. For \a n > 127 computes a series approximation, so that the * function won't overflow even for very large arguments. * * \ingroup mathematical_functions */ inline double LnFactorial( int n ) noexcept { PCL_PRECONDITION( n >= 0 ) if ( n <= FactorialCache::s_cacheSize ) return Ln( FactorialCache::s_lut[n] ); double x = n + 1; // return (x - 0.5)*Ln( x ) - x + 0.5*Ln( TwoPi() ) + 1/12/x - 1/(360*x*x*x); return (x - 0.5)*Ln( x ) - x + 0.91893853320467267 + 1/12/x - 1/(360*x*x*x); } /*! * \class Fact * \brief Factorial function. * * We use a static lookup table to speed up for \a n <= 127. * * Example of use: * * \code double factorialOfEight = Fact()( 8 ); // = 40320 \endcode * * The implementation of this class is thread-safe. * * \deprecated This class is deprecated and subject to removal in a future * version of PCL. For newly produced code, use the pcl::Factorial() and * pcl::LnFactorial() functions instead. * * \ingroup mathematical_functions */ template struct PCL_CLASS Fact : public FactorialCache { /*! * Returns the factorial of \a n ≥ 0. */ T operator()( int n ) const noexcept { PCL_PRECONDITION( n >= 0 ) if ( n <= s_cacheSize ) return T( s_lut[n] ); double x = s_lut[s_cacheSize]; for ( int m = s_cacheSize; ++m <= n; ) x *= m; return T( x ); } /*! * Returns the natural logarithm of the factorial of \a n ≥ 0. For * \a n <= 127 computes the natural logarithm of the factorial function * directly. For \a n > 127 computes a series approximation, so that the * function won't overflow even for very large arguments. */ T Ln( int n ) const noexcept { PCL_PRECONDITION( n >= 0 ) if ( n <= s_cacheSize ) return T( pcl::Ln( s_lut[n] ) ); double x = n + 1; // return T( (x - 0.5)*pcl::Ln( x ) - x + 0.5*pcl::Ln( TwoPi() ) + 1/12/x - 1/(360*x*x*x) ); return T( (x - 0.5)*pcl::Ln( x ) - x + 0.91893853320467267 + 1/12/x - 1/(360*x*x*x) ); } }; // ---------------------------------------------------------------------------- /*! * Natural (base e) logarithm of two. * \ingroup mathematical_functions */ inline constexpr long double Ln2() noexcept { return (long double)( 0.6931471805599453094172321214581766e+00L ); } // ---------------------------------------------------------------------------- /*! * Base 10 Logarithm of x. * \ingroup mathematical_functions */ template inline constexpr T Log( T x ) noexcept { PCL_PRECONDITION( x >= 0 ) return std::log10( x ); } // ---------------------------------------------------------------------------- /*! * Base 10 Logarithm of two. * \ingroup mathematical_functions */ inline constexpr long double Log2() noexcept { // Use the relation: // log10(2) = ln(2)/ln(10) return (long double)( 0.3010299956639811952137388947244930416265e+00L ); } // ---------------------------------------------------------------------------- /*! * Base 2 Logarithm of x. * \ingroup mathematical_functions */ template inline constexpr T Log2( T x ) noexcept { // Use the relation: // log2(x) = ln(x)/ln(2) PCL_PRECONDITION( x >= 0 ) return std::log( x )/Ln2(); } // ---------------------------------------------------------------------------- /*! * Base 2 Logarithm of e. * \ingroup mathematical_functions */ inline constexpr long double Log2e() noexcept { // Use the relation: // log2(e) = 1/ln(2) return (long double)( 0.14426950408889634073599246810018920709799e+01L ); } // ---------------------------------------------------------------------------- /*! * Base 2 Logarithm of ten. * \ingroup mathematical_functions */ inline constexpr long double Log2T() noexcept { // Use the relation: // log2(10) = 1/log(2) return (long double)( 0.33219280948873623478703194294893900118996e+01L ); } // ---------------------------------------------------------------------------- /*! * Base \a n logarithm of \a x. * \ingroup mathematical_functions */ template inline constexpr T LogN( T n, T x ) noexcept { PCL_PRECONDITION( x >= 0 ) return std::log( x )/std::log( n ); } // ---------------------------------------------------------------------------- /*! * Remainder of x/y. * \ingroup mathematical_functions */ template inline constexpr T Mod( T x, T y ) noexcept { return std::fmod( x, y ); } // ---------------------------------------------------------------------------- /*! * Horner's algorithm to evaluate the polynomial function with the specified * array \a c of \a n + 1 coefficients: * *
 * y = c[0] + c[1]*x + c[2]*x**2 + ... + c[n]*x**n
 * 
* * The array \a c of coefficients must provide contiguous storage for at least * \a n + 1 values of type T. The degree \a n must be >= 0; otherwise this * function invokes undefined behavior. * * \ingroup mathematical_functions */ template inline T Poly( T x, C c, int n ) noexcept { PCL_PRECONDITION( n >= 0 ) T y; for ( c += n, y = *c; n > 0; --n ) { y *= x; y += *--c; } return y; } /*! * Horner's algorithm to evaluate the polynomial function: * *
 * y = c[0] + c[1]*x + c[2]*x**2 + ... + c[n]*x**n
 * 
* * The specified coefficients initializer list \a c must not be empty; * otherwise this function invokes undefined behavior. * * \ingroup mathematical_functions */ template inline T Poly( T x, std::initializer_list c ) noexcept { PCL_PRECONDITION( c.size() > 0 ) return Poly( x, c.begin(), int( c.size() )-1 ); } // ---------------------------------------------------------------------------- /*! * Sign function: * *
 * -1 if x ≤ 0
 *  0 if x = 0
 * +1 if x ≥ 0
 * 
* * \ingroup mathematical_functions */ template inline constexpr int Sign( T x ) noexcept { return (x < 0) ? -1 : ((x > 0) ? +1 : 0); } // ---------------------------------------------------------------------------- /*! * Sign character: * *
 * '-' if x ≤ 0
 * ' ' if x = 0
 * '+' if x ≥ 0
 * 
* * \ingroup mathematical_functions */ template inline constexpr char SignChar( T x ) noexcept { return (x < 0) ? '-' : ((x > 0) ? '+' : ' '); } // ---------------------------------------------------------------------------- /*! * Sine function * \ingroup mathematical_functions */ template inline constexpr T Sin( T x ) noexcept { return std::sin( x ); } // ---------------------------------------------------------------------------- /*! * Hyperbolic Sine function. * \ingroup mathematical_functions */ template inline constexpr T Sinh( T x ) noexcept { return std::sinh( x ); } // ---------------------------------------------------------------------------- #ifdef __PCL_HAVE_SINCOS inline void __pcl_sincos__( float x, float& sx, float& cx ) noexcept { ::sincosf( x, &sx, &cx ); } inline void __pcl_sincos__( double x, double& sx, double& cx ) noexcept { ::sincos( x, &sx, &cx ); } inline void __pcl_sincos__( long double x, long double& sx, long double& cx ) noexcept { ::sincosl( x, &sx, &cx ); } #endif /*! * Sine and cosine of \a x. * * The arguments \a sx and \a cx will receive, respectively, the values of the * sine and cosine of x. * * If supported by the underlying standard math library, this function is * roughly twice as fast as calling Sin() and Cos() separately. For code that * spend a significant amount of time calculating sines and cosines, this * optimization is critical. * * \ingroup mathematical_functions */ template inline void SinCos( T x, T& sx, T& cx ) noexcept { #ifdef __PCL_HAVE_SINCOS __pcl_sincos__( x, sx, cx ); #else sx = std::sin( x ); cx = std::cos( x ); #endif } // ---------------------------------------------------------------------------- /*! * Integer and fractional parts of \a x. * * The arguments \a i and \a f receive, respectively, the integer (truncated) * part and the fractional part of \a x. It holds that \a x = \a i + \a f, i.e. * both \a i and \a f have the same sign as \a x. * * \ingroup mathematical_functions */ template inline void Split( T x, T& i, T& f ) noexcept { f = std::modf( x, &i ); } // ---------------------------------------------------------------------------- /*! * Square root function. * \ingroup mathematical_functions */ template inline constexpr T Sqrt( T x ) noexcept { return sqrt( x ); } // ---------------------------------------------------------------------------- /*! * Tangent function. * \ingroup mathematical_functions */ template inline constexpr T Tan( T x ) noexcept { return std::tan( x ); } // ---------------------------------------------------------------------------- /*! * Hyperbolic Tangent function. * \ingroup mathematical_functions */ template inline constexpr T Tanh( T x ) noexcept { return std::tanh( x ); } // ---------------------------------------------------------------------------- /*! * Truncated integer part of \a x. * \ingroup mathematical_functions */ template inline T Trunc( T x ) noexcept { (void)std::modf( x, &x ); return x; } // ---------------------------------------------------------------------------- #ifdef __PCL_HAVE_SSE2 inline int __pcl_trunci__( float x ) noexcept { return _mm_cvtt_ss2si( _mm_load_ss( &x ) ); } inline int __pcl_trunci__( double x ) noexcept { return _mm_cvttsd_si32( _mm_load_sd( &x ) ); } inline int __pcl_trunci__( long double x ) noexcept { return int( x ); } #endif /*! * TruncInt function: Truncated integer part of \a x as a 32-bit signed * integer. * * \note This is a performance-critical routine. It has been implemented using * high-performance, low-level techniques that may include inline assembly code * and/or compiler intrinsic functions. * * \ingroup mathematical_functions */ template inline int TruncInt( T x ) noexcept { PCL_PRECONDITION( x >= int_min && x <= int_max ) #ifdef __PCL_NO_PERFORMANCE_CRITICAL_MATH_ROUTINES return int( x ); #else # ifdef __PCL_HAVE_SSE2 return __pcl_trunci__( x ); # else return int( x ); # endif #endif } /*! * TruncI function: Truncated integer part of \a x as a 32-bit signed integer. * to a 32-bit signed integer. * * \deprecated Use TruncInt() in newly produced code. * * \ingroup mathematical_functions */ template inline int TruncI( T x ) noexcept { return TruncInt( x ); } #define TruncInt32( x ) TruncInt( x ) #define TruncI32( x ) TruncInt( x ) // ---------------------------------------------------------------------------- #ifdef __PCL_HAVE_SSE2 #if defined( __x86_64__ ) || defined( _M_X64 ) inline int64 __pcl_trunci64__( float x ) noexcept { return _mm_cvttss_si64( _mm_load_ss( &x ) ); } inline int64 __pcl_trunci64__( double x ) noexcept { return _mm_cvttsd_si64( _mm_load_sd( &x ) ); } #else inline int64 __pcl_trunci64__( float x ) noexcept { return int64( _mm_cvtt_ss2si( _mm_load_ss( &x ) ) ); } inline int64 __pcl_trunci64__( double x ) noexcept { return int64( x ); } #endif inline int64 __pcl_trunci64__( long double x ) noexcept { return int64( x ); } #endif // __PCL_HAVE_SSE2 /*! * TruncInt64 function: Truncated integer part of \a x as a 64-bit signed * integer. * * \note This is a performance-critical routine. It has been implemented using * high-performance, low-level techniques that may include inline assembly code * and/or compiler intrinsic functions. * * \ingroup mathematical_functions */ template inline int64 TruncInt64( T x ) noexcept { PCL_PRECONDITION( x >= int64_min && x <= int64_max ) #ifdef __PCL_NO_PERFORMANCE_CRITICAL_MATH_ROUTINES return int64( Trunc( x ) ); #else # ifdef __PCL_HAVE_SSE2 return __pcl_trunci64__( x ); # else return int64( Trunc( x ) ); # endif #endif } /*! * TruncI64 function: Truncated integer part of \a x as a 64-bit signed * integer. * * \deprecated Use TruncInt64() in newly produced code. * * \ingroup mathematical_functions */ template inline int64 TruncI64( T x ) noexcept { return TruncInt64( x ); } // ---------------------------------------------------------------------------- /*! * General power function: \a x raised to \a y. * * When you know some of the arguments in advance, faster alternatives are: * * \li Use Pow10I\()( y ) when x == 10 and y is an integer * \li Use PowI( x, y ) when x != 10 and y is an integer * \li Use Pow10( y ) when x == 10 and y is not an integer * * Otherwise, you can also use: Pow2( y*Log2( x ) ) * * \ingroup mathematical_functions */ template inline constexpr T Pow( T x, T y ) noexcept { PCL_PRECONDITION( y < T( int_max ) ) return std::pow( x, y ); } // ---------------------------------------------------------------------------- /*! * \class Pow10I * \brief Exponential function 10**n, \a n being a signed integer. * * Example of use: * * \code double x = Pow10I()( 5 ); // x = 10^5 \endcode * * \ingroup mathematical_functions */ template struct PCL_CLASS Pow10I { T operator ()( int n ) const noexcept { // Use fast table lookups and squaring up to |n| <= 50. static const T lut[] = { #define ___( x ) static_cast( x ) ___( 1.0e+00 ), ___( 1.0e+01 ), ___( 1.0e+02 ), ___( 1.0e+03 ), ___( 1.0e+04 ), ___( 1.0e+05 ), ___( 1.0e+06 ), ___( 1.0e+07 ), ___( 1.0e+08 ), ___( 1.0e+09 ), ___( 1.0e+10 ), ___( 1.0e+11 ), ___( 1.0e+12 ), ___( 1.0e+13 ), ___( 1.0e+14 ), ___( 1.0e+15 ), ___( 1.0e+16 ), ___( 1.0e+17 ), ___( 1.0e+18 ), ___( 1.0e+19 ), ___( 1.0e+20 ), ___( 1.0e+21 ), ___( 1.0e+22 ), ___( 1.0e+23 ), ___( 1.0e+24 ), ___( 1.0e+25 ), ___( 1.0e+26 ), ___( 1.0e+27 ), ___( 1.0e+28 ), ___( 1.0e+29 ), ___( 1.0e+30 ), ___( 1.0e+31 ), ___( 1.0e+32 ), ___( 1.0e+33 ), ___( 1.0e+34 ), ___( 1.0e+35 ), ___( 1.0e+36 ), ___( 1.0e+37 ), ___( 1.0e+38 ), ___( 1.0e+39 ), ___( 1.0e+40 ), ___( 1.0e+41 ), ___( 1.0e+42 ), ___( 1.0e+43 ), ___( 1.0e+44 ), ___( 1.0e+45 ), ___( 1.0e+46 ), ___( 1.0e+47 ), ___( 1.0e+48 ), ___( 1.0e+49 ) #undef ___ }; static const int N = ItemsInArray( lut ); int i = ::abs( n ); double x; if ( i < N ) x = lut[i]; else { x = lut[N-1]; while ( (i -= N-1) >= N ) x *= x; if ( i != 0 ) x *= lut[i]; } return T( (n >= 0) ? x : 1/x ); } }; // ---------------------------------------------------------------------------- /*! * The exponential function 10**x. * \ingroup mathematical_functions */ template inline T Pow10( T x ) noexcept { int i = TruncInt( x ); return (i == x) ? Pow10I()( i ) : T( std::pow( 10, x ) ); } // ---------------------------------------------------------------------------- /*! * Bitwise rotate left function: Rotates \a x to the left by \a n bits. * * The template argument T must be an unsigned arithmetic type (uint8, uint16, * uint32 or uint64). The bit count \a n must be smaller than the number of * bits required to store an instance of T; for example, if T is uint32, \a n * must be in the range [0,31]. * * \ingroup mathematical_functions */ template inline T RotL( T x, uint32 n ) noexcept { static_assert( std::is_unsigned::value, "RotL() can only be used for unsigned integer scalar types" ); const uint8 mask = 8*sizeof( x ) - 1; const uint8 r = uint8( n & mask ); return (x << r) | (x >> ((-r) & mask)); // Or equivalently, but less optimized: //return (x << r) | (x >> (1+mask-r)); } /*! * Bitwise rotate right function: Rotates \a x to the right by \a n bits. * * The template argument T must be an unsigned arithmetic type (uint8, uint16, * uint32 or uint64). The bit count \a n must be smaller than the number of * bits required to store an instance of T; for example, if T is uint32, \a n * must be in the range [0,31]. * * \ingroup mathematical_functions */ template inline T RotR( T x, uint32 n ) noexcept { static_assert( std::is_unsigned::value, "RotR() can only be used for unsigned integer scalar types" ); const uint8 mask = 8*sizeof( x ) - 1; const uint8 r = uint8( n & mask ); return (x >> r) | (x << ((-r) & mask)); // Or equivalently, but less optimized: //return (x >> r) | (x << (1+mask-r)); } // ---------------------------------------------------------------------------- /*! * Round function: x rounded to the nearest integer (double precision version). * * \note This is a performance-critical routine. It has been implemented using * high-performance, low-level techniques that may include inline assembly code * and/or compiler intrinsic functions. * * \ingroup mathematical_functions */ inline double Round( double x ) noexcept { #ifdef __PCL_NO_PERFORMANCE_CRITICAL_MATH_ROUTINES return floor( x + 0.5 ); #else # ifdef _MSC_VER # ifdef _M_X64 return double( _mm_cvtsd_si64( _mm_load_sd( &x ) ) ); # else __asm fld x __asm frndint # endif # else double r; asm volatile( "frndint\n": "=t" (r) : "0" (x) ); return r; # endif #endif } /*! * Round function: x rounded to the nearest integer (single precision version). * * \note This is a performance-critical routine. It has been implemented using * high-performance, low-level techniques that may include inline assembly code * and/or compiler intrinsic functions. * * \ingroup mathematical_functions */ inline float Round( float x ) noexcept { #ifdef __PCL_NO_PERFORMANCE_CRITICAL_MATH_ROUTINES return floorf( x + 0.5F ); #else # ifdef _MSC_VER # ifdef _M_X64 return float( _mm_cvtss_si32( _mm_load_ss( &x ) ) ); # else __asm fld x __asm frndint # endif # else float r; asm volatile( "frndint\n": "=t" (r) : "0" (x) ); return r; # endif #endif } /*! * Round function: x rounded to the nearest integer (long double version). * * \note This is a performance-critical routine. It has been implemented using * high-performance, low-level techniques that may include inline assembly code * and/or compiler intrinsic functions. * * \ingroup mathematical_functions */ inline long double Round( long double x ) noexcept { #ifdef __PCL_NO_PERFORMANCE_CRITICAL_MATH_ROUTINES return floorl( x + 0.5L ); #else # ifdef _MSC_VER # ifdef _M_X64 double _x = x; return (long double)_mm_cvtsd_si64( _mm_load_sd( &_x ) ); # else __asm fld x __asm frndint # endif # else long double r; asm volatile( "frndint\n": "=t" (r) : "0" (x) ); return r; # endif #endif } // ---------------------------------------------------------------------------- /*! * RoundInt function: Rounds \a x to the nearest integer and converts the * result to a 32-bit signed integer. * * This function follows the Banker's rounding rule: a perfect half is always * rounded to the nearest even digit. Some examples: * *
 * RoundInt( 0.5 ) -> 0
 * RoundInt( 1.5 ) -> 2
 * RoundInt( 2.5 ) -> 2
 * RoundInt( 3.5 ) -> 4
 * 
* * By contrast, arithmetic rounding rounds a perfect half to the nearest digit, * either odd or even. For example: * *
 * RoundIntArithmetic( 0.5 ) -> 1
 * RoundIntArithmetic( 1.5 ) -> 2
 * RoundIntArithmetic( 2.5 ) -> 3
 * RoundIntArithmetic( 3.5 ) -> 4
 * 
* * Banker's rounding (also known as Gaussian rounding) is statistically more * accurate than the usual arithmetic rounding, but it causes aliasing problems * in some specific algorithms that depend critically on uniform rounding, such * as nearest neighbor upsampling. * * \note This is a performance-critical routine. It has been implemented using * high-performance, low-level techniques that may include inline assembly code * and/or compiler intrinsic functions. * * \sa RoundIntArithmetic(), RoundIntBanker() * * \ingroup mathematical_functions */ template inline int RoundInt( T x ) noexcept { PCL_PRECONDITION( x >= int_min && x <= int_max ) #ifdef __PCL_NO_PERFORMANCE_CRITICAL_MATH_ROUTINES return int( Round( x ) ); #else volatile union { double d; int32 i; } v = { x + 6755399441055744.0 }; return v.i; // ### NB: Assuming little-endian architecture. /* ### Deprecated code - The above code based on magic numbers is faster and more portable across platforms and compilers. // Default FPU rounding mode assumed to be nearest integer. int r; # ifdef _MSC_VER __asm fld x __asm fistp dword ptr r # else asm volatile( "fistpl %0\n" : "=m" (r) : "t" (x) : "st" ); # endif return r; */ #endif } /*! * RoundI function: Rounds \a x to the nearest integer and converts the result * to a 32-bit signed integer. * * \deprecated Use RoundInt() in newly produced code. * * \ingroup mathematical_functions */ template inline int RoundI( T x ) noexcept { return RoundInt( x ); } /*! * Rounds \a x to the nearest integer using the Banker's rounding rule, and * converts the result to a 32-bit signed integer. * * This function is a convenience synonym for RoundInt(). * * \ingroup mathematical_functions */ template inline int RoundIntBanker( T x ) noexcept { return RoundInt( x ); } /*! * Rounds \a x to the nearest integer using the arithmetic rounding rule, and * converts the result to a 32-bit signed integer. * * Arithmetic rounding rounds a perfect half to the nearest digit, either odd * or even. For example: * *
 * RoundIntArithmetic( 0.5 ) -> 1
 * RoundIntArithmetic( 1.5 ) -> 2
 * RoundIntArithmetic( 2.5 ) -> 3
 * RoundIntArithmetic( 3.5 ) -> 4
 * 
* * See the RoundInt() function for more information on rounding rules. * * \note This is a performance-critical routine. It has been implemented using * high-performance, low-level techniques that may include inline assembly code * and/or compiler intrinsic functions. * * \sa RoundInt(), RoundIntBanker() * * \ingroup mathematical_functions */ template inline int RoundIntArithmetic( T x ) noexcept { PCL_PRECONDITION( x >= int_min && x <= int_max ) int i = TruncInt( x ); if ( i < 0 ) { if ( x - i <= T( -0.5 ) ) return i-1; } else { if ( x - i >= T( +0.5 ) ) return i+1; } return i; } // ---------------------------------------------------------------------------- /*! * RoundInt64 function: Rounds \a x to the nearest integer and converts the * result to a 64-bit signed integer. * * Since the default IEEE 754 rounding mode follows Banker's rounding rule, * this is what you should expect when calling this function. See the * documentation for RoundInt() for more information on rounding modes. * * \note This is a performance-critical routine. It has been implemented using * high-performance, low-level techniques that may include inline assembly code * and/or compiler intrinsic functions. * * \ingroup mathematical_functions */ inline int64 RoundInt64( double x ) noexcept { #ifdef __PCL_NO_PERFORMANCE_CRITICAL_MATH_ROUTINES return int64( Round( x ) ); #else // ### N.B.: Default FPU rounding mode assumed to be nearest integer. # ifdef _MSC_VER # ifdef _M_X64 return _mm_cvtsd_si64( _mm_load_sd( &x ) ); # else int64 r; __asm fld x __asm fistp qword ptr r return r; # endif # else int64 r; asm volatile( "fistpll %0\n" : "=m" (r) : "t" (x) : "st" ); return r; # endif #endif } /*! * RoundI64 function: Rounds \a x to the nearest integer and converts the * result to a 64-bit signed integer. * * \deprecated Use RoundInt64() in newly produced code. */ inline int64 RoundI64( double x ) noexcept { return RoundInt64( x ); } /*! * Rounds \a x to the nearest integer using the arithmetic rounding rule, and * converts the result to a 64-bit signed integer. * * Arithmetic rounding rounds a perfect half to the nearest digit, either odd * or even. For example: * *
 * RoundIntArithmetic( 0.5 ) -> 1
 * RoundIntArithmetic( 1.5 ) -> 2
 * RoundIntArithmetic( 2.5 ) -> 3
 * RoundIntArithmetic( 3.5 ) -> 4
 * 
* * See the RoundInt() function for more information on rounding rules. * * \note This is a performance-critical routine. It has been implemented using * high-performance, low-level techniques that may include inline assembly code * and/or compiler intrinsic functions. * * \sa RoundInt(), RoundIntBanker() * * \ingroup mathematical_functions */ inline int64 RoundInt64Arithmetic( double x ) noexcept { int64 i = TruncInt64( x ); if ( i < 0 ) { if ( x - i <= -0.5 ) return i-1; } else { if ( x - i >= +0.5 ) return i+1; } return i; } // ---------------------------------------------------------------------------- /*! * General rounding function: \a x rounded to \a n fractional digits. * \ingroup mathematical_functions */ template inline T Round( T x, int n ) noexcept { PCL_PRECONDITION( n >= 0 ) T p = Pow10I()( n ); return Round( p*x )/p; } // ---------------------------------------------------------------------------- /*! * The exponential function 2**x. * \ingroup mathematical_functions */ template inline constexpr T Pow2( T x ) noexcept { // Use the relation: // 2**x = e**(x*ln(2)) return Exp( x*Ln2() ); } // ---------------------------------------------------------------------------- /*! * \class Pow2I * \brief Exponential function 2**n, \a n being a signed integer. * * Example of use: * * \code float x = Pow2I()( -2 ); // x = 1/4 \endcode * * \ingroup mathematical_functions */ template struct PCL_CLASS Pow2I { T operator ()( int n ) const noexcept { // We shift left a single bit in 31-bit chunks. int i = ::abs( n ), p; double x = uint32( 1 ) << (p = Min( i, 31 )); while ( (i -= p) != 0 ) x *= uint32( 1 ) << (p = Min( i, 31 )); return T( (n >= 0) ? x : 1/x ); } }; // ---------------------------------------------------------------------------- /*! * The exponential function x**n, where \a n is a signed integer. * \ingroup mathematical_functions */ template inline T PowI( T x, int n ) noexcept { if ( n == 0 ) return T( 1 ); T r = x; int i = ::abs( n ); if ( i > 1 ) { do r *= r; while ( (i >>= 1) > 1 ); if ( n & 1 ) r *= x; } return (n > 0) ? r : T( 1/r ); } /*! * Returns \a x raised to the 4th power. * \ingroup mathematical_functions */ template inline T PowI4( T x ) noexcept { x *= x; return x*x; } /*! * Returns \a x raised to the 6th power. * \ingroup mathematical_functions */ template inline T PowI6( T x ) noexcept { x *= x*x; return x*x; } /*! * Returns \a x raised to the 8th power. * \ingroup mathematical_functions */ template inline T PowI8( T x ) noexcept { x *= x*x*x; return x*x; } /*! * Returns \a x raised to the 10th power. * \ingroup mathematical_functions */ template inline T PowI10( T x ) noexcept { x *= x*x*x*x; return x*x; } /*! * Returns \a x raised to the 12th power. * \ingroup mathematical_functions */ template inline T PowI12( T x ) noexcept { x *= x*x*x*x*x; return x*x; } // ---------------------------------------------------------------------------- /*! * Inverse hyperbolic sine function. * * ArcSinh( x ) = Ln( x + Sqrt( 1 + x**2 ) ) * * \ingroup mathematical_functions */ template inline constexpr T ArcSinh( T x ) noexcept { #ifndef __PCL_NO_STD_INV_HYP_TRIG_FUNCTIONS return std::asinh( x ); #else return Ln( x + Sqrt( 1 + x*x ) ); #endif } // ---------------------------------------------------------------------------- /*! * Inverse hyperbolic cosine function. * * ArcCosh( x ) = 2*Ln( Sqrt( (x + 1)/2 ) + Sqrt( (x - 1)/2 ) ) * * \ingroup mathematical_functions */ template inline constexpr T ArcCosh( T x ) noexcept { #ifndef __PCL_NO_STD_INV_HYP_TRIG_FUNCTIONS return std::acosh( x ); #else return 2*Ln( Sqrt( (x + 1)/2 ) + Sqrt( (x - 1)/2 ) ); #endif } // ---------------------------------------------------------------------------- /*! * Inverse hyperbolic tangent function. * * ArcTanh( x ) = (Ln( 1 + x ) - Ln( 1 - x ))/2 * * \ingroup mathematical_functions */ template inline constexpr T ArcTanh( T x ) noexcept { #ifndef __PCL_NO_STD_INV_HYP_TRIG_FUNCTIONS return std::atanh( x ); #else return (Ln( 1 + x ) - Ln( 1 - x ))/2; #endif } // ---------------------------------------------------------------------------- /*! * Inverse haversine (archaversine) function: * * ArcHav( x ) = 2*ArcSin( Sqrt( x ) ) * * The haversine is useful to work with tiny angles. * * \ingroup mathematical_functions */ template inline constexpr T ArcHav( T x ) noexcept { return 2*ArcSin( Sqrt( x ) ); } // ---------------------------------------------------------------------------- /*! * Conversion from degrees to radians. * \ingroup mathematical_functions */ template inline constexpr T Rad( T x ) noexcept { return static_cast( 0.174532925199432957692369076848861272222e-01L * x ); } // ---------------------------------------------------------------------------- /*! * Conversion from radians to arcminutes. * \ingroup mathematical_functions */ template inline constexpr T RadMin( T x ) noexcept { return Deg( x )*60; } // ---------------------------------------------------------------------------- /*! * Conversion from radians to arcseconds. * \ingroup mathematical_functions */ template inline constexpr T RadSec( T x ) noexcept { return Deg( x )*3600; } // ---------------------------------------------------------------------------- /*! * Conversion from arcminutes to radians. * \ingroup mathematical_functions */ template inline constexpr T MinRad( T x ) noexcept { return Rad( x/60 ); } // ---------------------------------------------------------------------------- /*! * Conversion from arcseconds to radians. * \ingroup mathematical_functions */ template inline constexpr T SecRad( T x ) noexcept { return Rad( x/3600 ); } /*! * Conversion from arcseconds to radians (a synonym for SecRad()). * \ingroup mathematical_functions */ template inline constexpr T AsRad( T x ) noexcept { return SecRad( x ); } // ---------------------------------------------------------------------------- /*! * Conversion from milliarcseconds (mas) to radians. * \ingroup mathematical_functions */ template inline constexpr T MasRad( T x ) noexcept { return Rad( x/3600000 ); } // ---------------------------------------------------------------------------- /*! * Conversion from microarcseconds (uas) to radians. * \ingroup mathematical_functions */ template inline constexpr T UasRad( T x ) noexcept { return Rad( x/3600000000 ); } // ---------------------------------------------------------------------------- /*! * An angle in radians reduced to the [-pi,+pi] range. * \ingroup mathematical_functions */ template inline constexpr T ModPi( T x ) noexcept { x = Mod( x + static_cast( Pi() ), static_cast( TwoPi() ) ) - static_cast( Pi() ); return (x < -static_cast( Pi() )) ? x + static_cast( TwoPi() ) : x; } // ---------------------------------------------------------------------------- /*! * An angle in radians reduced to the (-2pi,+2pi) range, that is, the remainder * of x/(2*pi). * \ingroup mathematical_functions */ template inline constexpr T Mod2Pi( T x ) noexcept { return Mod( x, static_cast( TwoPi() ) ); } // ---------------------------------------------------------------------------- /*! * An angle in radians normalized to the [0,2pi) range. * \ingroup mathematical_functions */ template inline constexpr T Norm2Pi( T x ) noexcept { return ((x = Mod2Pi( x )) < 0) ? x + static_cast( TwoPi() ) : x; } // ---------------------------------------------------------------------------- /*! * Rotates a point on the plane. * * \param[out] x,y %Point coordinates. On output, these variables will * receive the corresponding rotated coordinates. * * \param sa, ca Sine and cosine of the rotation angle. * * \param xc,yc Coordinates of the center of rotation. * * \ingroup mathematical_functions */ template inline void Rotate( T& x, T& y, T1 sa, T1 ca, T2 xc, T2 yc ) noexcept { T1 dx = T1( x ) - T1( xc ); T1 dy = T1( y ) - T1( yc ); x = T( T1( xc ) + ca*dx - sa*dy ); y = T( T1( yc ) + sa*dx + ca*dy ); } /*! * Rotates a point on the plane. * * This is a template instantiation of Rotate( T&, T&, T1, T1, T2, T2 ) for * the \c int type. * * Rotated coordinates are rounded to the nearest integers. * * \ingroup mathematical_functions */ template inline void Rotate( int& x, int& y, T1 sa, T1 ca, T2 xc, T2 yc ) noexcept { T1 dx = T1( x ) - T1( xc ); T1 dy = T1( y ) - T1( yc ); x = RoundInt( T1( xc ) + ca*dx - sa*dy ); y = RoundInt( T1( yc ) + sa*dx + ca*dy ); } /*! * Rotates a point on the plane. * * This is a template instantiation of Rotate( T&, T&, T1, T1, T2, T2 ) for * the \c long type. * * Rotated coordinates are rounded to the nearest integers. * * \ingroup mathematical_functions */ template inline void Rotate( long& x, long& y, T1 sa, T1 ca, T2 xc, T2 yc ) noexcept { T1 dx = T1( x ) - T1( xc ); T1 dy = T1( y ) - T1( yc ); x = (long)RoundInt( T1( xc ) + ca*dx - sa*dy ); y = (long)RoundInt( T1( yc ) + sa*dx + ca*dy ); } /*! * Rotates a point on the plane. * * This is a template instantiation of Rotate( T&, T&, T1, T1, T2, T2 ) for * the \c int64 type. * * Rotated coordinates are rounded to the nearest integers. * * \ingroup mathematical_functions */ template inline void Rotate( int64& x, int64& y, T1 sa, T1 ca, T2 xc, T2 yc ) noexcept { T1 dx = T1( x ) - T1( xc ); T1 dy = T1( y ) - T1( yc ); x = RoundInt64( T1( xc ) + ca*dx - sa*dy ); y = RoundInt64( T1( yc ) + sa*dx + ca*dy ); } /*! * Rotates a point on the plane. * * \param[out] x,y %Point coordinates. On output, these variables will * receive the corresponding rotated coordinates. * * \param a Rotation angle in radians. * * \param xc,yc Coordinates of the center of rotation. * * Instantiations for integer types round rotated coordinated to the nearest * integers. * * \ingroup mathematical_functions */ template inline void Rotate( T& x, T& y, T1 a, T2 xc, T2 yc ) noexcept { T1 sa, ca; SinCos( a, sa, ca ); Rotate( x, y, sa, ca, xc, yc ); } // ---------------------------------------------------------------------------- template inline N __pcl_norm__( const T* i, const T* j, const P& p, N* ) noexcept { PCL_PRECONDITION( p > P( 0 ) ) N n = N( 0 ); for ( ; i < j; ++i ) n += Pow( Abs( N( *i ) ), N( p ) ); return Pow( n, N( 1/p ) ); } /*! * Computes the norm of the elements in the sequence [i,j). For any real p > 0, * the norm N is given by: * *
 * N = sum( abs( x )^p )^(1/p)
 * 
* * for all x in [i,j). * * \ingroup mathematical_functions * \sa L1Norm(), L2Norm() */ template inline T Norm( const T* i, const T* j, const P& p ) noexcept { return __pcl_norm__( i, j, p, (T*)( 0 ) ); } template inline double Norm( const float* i, const float* j, const P& p ) noexcept { return __pcl_norm__( i, j, p, (double*)( 0 ) ); } template inline double Norm( const int* i, const int* j, const P& p ) noexcept { return __pcl_norm__( i, j, p, (double*)( 0 ) ); } template inline double Norm( const unsigned* i, const unsigned* j, const P& p ) noexcept { return __pcl_norm__( i, j, p, (double*)( 0 ) ); } template inline double Norm( const int8* i, const int8* j, const P& p ) noexcept { return __pcl_norm__( i, j, p, (double*)( 0 ) ); } template inline double Norm( const uint8* i, const uint8* j, const P& p ) noexcept { return __pcl_norm__( i, j, p, (double*)( 0 ) ); } template inline double Norm( const int16* i, const int16* j, const P& p ) noexcept { return __pcl_norm__( i, j, p, (double*)( 0 ) ); } template inline double Norm( const uint16* i, const uint16* j, const P& p ) noexcept { return __pcl_norm__( i, j, p, (double*)( 0 ) ); } template inline double Norm( const int64* i, const int64* j, const P& p ) noexcept { return __pcl_norm__( i, j, p, (double*)( 0 ) ); } template inline double Norm( const uint64* i, const uint64* j, const P& p ) noexcept { return __pcl_norm__( i, j, p, (double*)( 0 ) ); } // ---------------------------------------------------------------------------- template inline N __pcl_l1norm__( const T* i, const T* j, N* ) noexcept { N n = N( 0 ); for ( ; i < j; ++i ) n += N( Abs( *i ) ); return n; } /*! * Computes the L1 norm (or Manhattan norm) of the elements in the sequence * [i,j). The L1 norm is the sum of the absolute values of the elements. * * \ingroup mathematical_functions */ template inline T L1Norm( const T* i, const T* j ) noexcept { return __pcl_l1norm__( i, j, (T*)( 0 ) ); } inline double L1Norm( const float* i, const float* j ) noexcept { return __pcl_l1norm__( i, j, (double*)( 0 ) ); } inline double L1Norm( const int* i, const int* j ) noexcept { return __pcl_l1norm__( i, j, (double*)( 0 ) ); } inline double L1Norm( const unsigned* i, const unsigned* j ) noexcept { return __pcl_l1norm__( i, j, (double*)( 0 ) ); } inline double L1Norm( const int8* i, const int8* j ) noexcept { return __pcl_l1norm__( i, j, (double*)( 0 ) ); } inline double L1Norm( const uint8* i, const uint8* j ) noexcept { return __pcl_l1norm__( i, j, (double*)( 0 ) ); } inline double L1Norm( const int16* i, const int16* j ) noexcept { return __pcl_l1norm__( i, j, (double*)( 0 ) ); } inline double L1Norm( const uint16* i, const uint16* j ) noexcept { return __pcl_l1norm__( i, j, (double*)( 0 ) ); } inline double L1Norm( const int64* i, const int64* j ) noexcept { return __pcl_l1norm__( i, j, (double*)( 0 ) ); } inline double L1Norm( const uint64* i, const uint64* j ) noexcept { return __pcl_l1norm__( i, j, (double*)( 0 ) ); } // ---------------------------------------------------------------------------- template inline N __pcl_l2norm__( const T* i, const T* j, N* ) noexcept { N n = N( 0 ); for ( ; i < j; ++i ) n += N( *i ) * N( *i ); return Sqrt( n ); } /*! * Computes the L2 norm (or Euclidean norm) of the elements in the sequence * [i,j). The L2 norm is the square root of the sum of squared elements. * * \ingroup mathematical_functions */ template inline T L2Norm( const T* i, const T* j ) noexcept { return __pcl_l2norm__( i, j, (T*)( 0 ) ); } inline double L2Norm( const float* i, const float* j ) noexcept { return __pcl_l2norm__( i, j, (double*)( 0 ) ); } inline double L2Norm( const int* i, const int* j ) noexcept { return __pcl_l2norm__( i, j, (double*)( 0 ) ); } inline double L2Norm( const unsigned* i, const unsigned* j ) noexcept { return __pcl_l2norm__( i, j, (double*)( 0 ) ); } inline double L2Norm( const int8* i, const int8* j ) noexcept { return __pcl_l2norm__( i, j, (double*)( 0 ) ); } inline double L2Norm( const uint8* i, const uint8* j ) noexcept { return __pcl_l2norm__( i, j, (double*)( 0 ) ); } inline double L2Norm( const int16* i, const int16* j ) noexcept { return __pcl_l2norm__( i, j, (double*)( 0 ) ); } inline double L2Norm( const uint16* i, const uint16* j ) noexcept { return __pcl_l2norm__( i, j, (double*)( 0 ) ); } inline double L2Norm( const int64* i, const int64* j ) noexcept { return __pcl_l2norm__( i, j, (double*)( 0 ) ); } inline double L2Norm( const uint64* i, const uint64* j ) noexcept { return __pcl_l2norm__( i, j, (double*)( 0 ) ); } // ---------------------------------------------------------------------------- /*! * Computes the L2 norm (or Euclidean norm) of the elements in the sequence * [i,j). This function is a synonym for L2Norm(). * * \ingroup mathematical_functions */ template inline T Norm( const T* i, const T* j ) noexcept { return L2Norm( i, j ); } inline double Norm( const float* i, const float* j ) noexcept { return __pcl_l2norm__( i, j, (double*)( 0 ) ); } inline double Norm( const int* i, const int* j ) noexcept { return __pcl_l2norm__( i, j, (double*)( 0 ) ); } inline double Norm( const unsigned* i, const unsigned* j ) noexcept { return __pcl_l2norm__( i, j, (double*)( 0 ) ); } inline double Norm( const int8* i, const int8* j ) noexcept { return __pcl_l2norm__( i, j, (double*)( 0 ) ); } inline double Norm( const uint8* i, const uint8* j ) noexcept { return __pcl_l2norm__( i, j, (double*)( 0 ) ); } inline double Norm( const int16* i, const int16* j ) noexcept { return __pcl_l2norm__( i, j, (double*)( 0 ) ); } inline double Norm( const uint16* i, const uint16* j ) noexcept { return __pcl_l2norm__( i, j, (double*)( 0 ) ); } inline double Norm( const int64* i, const int64* j ) noexcept { return __pcl_l2norm__( i, j, (double*)( 0 ) ); } inline double Norm( const uint64* i, const uint64* j ) noexcept { return __pcl_l2norm__( i, j, (double*)( 0 ) ); } // ---------------------------------------------------------------------------- /*! * Computes the Julian date (JD) corresponding to a time point expressed as a * date and a day fraction, providing the result by its separate integer and * fractional parts. * * \param[out] jdi On output, the integer part of the resulting JD. * * \param[out] jdf On output, the fractional part of the resulting JD. * * \param year The year of the date. Positive and negative years are * supported. Years are counted arithmetically: the year zero * is the year before the year +1, that is, what historians * call the year 1 B.C. * * \param month The month of the date. Usually in the [1,12] range but can * be any integer number. * * \param day The day of the date. Usually in the [1,31] range but can * be any integer number. * * \param dayf The day fraction. The default value is zero, which * computes the JD at zero hours. Usually in the [0,1) range * but can be any real number. * * This routine, as well as JDToCalendarTime(), implement modified versions of * the original algorithms due to Jean Meeus. Our modifications allow for * negative Julian dates, which extends the range of allowed dates to the past * considerably. We developed these modifications in the context of large-scale * solar system ephemeris calculations. * * The computed value is the JD corresponding to the specified date and day * fraction, which is equal to the sum of the \a jdi and \a jdf variables. * * \b References * * Meeus, Jean (1991), Astronomical Algorithms, Willmann-Bell, Inc., * chapter 7. * * \ingroup mathematical_functions */ void PCL_FUNC CalendarTimeToJD( int& jdi, double& jdf, int year, int month, int day, double dayf = 0 ) noexcept; /*! * Computes the Julian date (JD) corresponding to a time point expressed as a * date and a day fraction. * * \param year The year of the date. Positive and negative years are * supported. Years are counted arithmetically: the year zero is * the year before the year +1, that is, what historians call * the year 1 B.C. * * \param month The month of the date. Usually in the [1,12] range but can be * any integer number. * * \param day The day of the date. Usually in the [1,31] range but can be * any integer number. * * \param dayf The day fraction. The default value is zero, which computes * the JD at zero hours. Usually in the [0,1) range but can be * any real number. * * This routine, as well as JDToCalendarTime(), implement modified versions of * the original algorithms due to Jean Meeus. Our modifications allow for * negative Julian dates, which extends the range of allowed dates to the past * considerably. We developed these modifications in the context of large-scale * solar system ephemeris calculations. * * The returned value is the JD corresponding to the specified date and day * fraction. * * Because of the numerical precision of the double type (IEEE 64-bit floating * point), this routine can return JD values accurate only to within one * millisecond. * * \b References * * Meeus, Jean (1991), Astronomical Algorithms, Willmann-Bell, Inc., * chapter 7. * * \ingroup mathematical_functions */ inline double CalendarTimeToJD( int year, int month, int day, double dayf = 0 ) noexcept { int jdi; double jdf; CalendarTimeToJD( jdi, jdf, year, month, day, dayf ); return jdi + jdf; } /*! * Computes the date and day fraction corresponding to a time point expressed * as a Julian date (JD), specified by its separate integer and fractional * parts. * * \param[out] year On output, this variable receives the year of the * resulting date. * * \param[out] month On output, this variable receives the month of the * resulting date in the range [1,12]. * * \param[out] day On output, this variable receives the day of the * resulting date in the range [1,31]. Different month day * counts and leap years are taken into account, so the * returned day corresponds to an existing calendar date. * * \param[out] dayf On output, this variable receives the day fraction for the * specified time point, in the [0,1) range. * * \param jdi The integer part of the input Julian date. * * \param jdf The fractional part of the input Julian date. * * The input time point must be equal to the sum of \a jdi and \a jdf. * * For more information about the implemented algorithms and references, see * the documentation for CalendarTimeToJD(). * * \ingroup mathematical_functions */ void PCL_FUNC JDToCalendarTime( int& year, int& month, int& day, double& dayf, int jdi, double jdf ) noexcept; /*! * Computes the date and day fraction corresponding to a time point expressed * as a Julian date (JD). * * \param[out] year On output, this variable receives the year of the * resulting date. * * \param[out] month On output, this variable receives the month of the * resulting date in the range [1,12]. * * \param[out] day On output, this variable receives the day of the * resulting date in the range [1,31]. Different month day * counts and leap years are taken into account, so the * returned day corresponds to an existing calendar date. * * \param[out] dayf On output, this variable receives the day fraction for the * specified time point, in the [0,1) range. * * \param jd The input time point as a Julian date. * * Because of the numerical precision of the double type (IEEE 64-bit floating * point), this routine can handle JD values accurate only to within one * millisecond. * * For more information about the implemented algorithms and references, see * the documentation for CalendarTimeToJD(). * * \ingroup mathematical_functions */ inline void JDToCalendarTime( int& year, int& month, int& day, double& dayf, double jd ) noexcept { JDToCalendarTime( year, month, day, dayf, TruncInt( jd ), Frac( jd ) ); } // ---------------------------------------------------------------------------- /*! * Conversion of a decimal scalar \a d to the equivalent sexagesimal decimal * components \a sign, \a s1, \a s2 and \a s3, such that: * *
 * d = sign * (s1 + (s2 + s3/60)/60)
 * 
* * with the following constraints: * *
 * sign = -1 iff d < 0
 * sign = +1 iff d ≥ 0
 * 0 ≤ s1
 * 0 ≤ s2 < 60
 * 0 ≤ s3 < 60
 * 
* * \ingroup mathematical_functions */ template inline void DecimalToSexagesimal( int& sign, S1& s1, S2& s2, S3& s3, const D& d ) noexcept { double t1 = Abs( d ); double t2 = Frac( t1 )*60; double t3 = Frac( t2 )*60; sign = (d < 0) ? -1 : +1; s1 = S1( TruncInt( t1 ) ); s2 = S2( TruncInt( t2 ) ); s3 = S3( t3 ); } /*! * Conversion of the sexagesimal decimal components \a sign, \a s1, \a s2 and * \a s3 to their equivalent decimal scalar. The returned value is equal to: * *
 * ((sign < 0) ? -1 : +1)*(Abs( s1 ) + (s2 + s3/60)/60);
 * 
* * \ingroup mathematical_functions */ template inline double SexagesimalToDecimal( int sign, const S1& s1, const S2& s2 = S2( 0 ), const S3& s3 = S3( 0 ) ) noexcept { double d = Abs( s1 ) + (s2 + s3/60)/60; return (sign < 0) ? -d : d; } // ---------------------------------------------------------------------------- /*! * \defgroup statistical_functions Statistical Functions */ /*! * Returns the sum of elements in a sequence [i,j). * * For empty sequences, this function returns zero. * * This is a straight implementation of a floating point sum, which is subject * to severe roundoff errors if the number of summed elements is large. One way * to improve on this problem is to sort the input set by decreasing order of * absolute value \e before calling this function. A much better solution, but * computationally expensive, is a compensated summation algorithm such as * Kahan summation, which we have implemented in the StableSum() routine. * * \ingroup statistical_functions */ template inline double Sum( const T* __restrict__ i, const T* __restrict__ j ) noexcept { double sum = 0; while ( i < j ) sum += double( *i++ ); return sum; } /*! * Computes the sum of elements in a sequence [i,j) using a numerically stable * summation algorithm to minimize roundoff error. * * For empty sequences, this function returns zero. * * In the current PCL versions, this function implements the Kahan summation * algorithm to reduce roundoff error to the machine's floating point error. * * \ingroup statistical_functions */ template inline double StableSum( const T* __restrict__ i, const T* __restrict__ j ) noexcept { double sum = 0; double eps = 0; while ( i < j ) { double y = double( *i++ ) - eps; double t = sum + y; eps = (t - sum) - y; sum = t; } return sum; } /*! * Returns the sum of the absolute values of the elements in a sequence [i,j). * * For empty sequences, this function returns zero. * * See the remarks made for the Sum() function, which are equally applicable in * this case. See StableModulus() for a (slow) numerically stable version of * this function. * * \ingroup statistical_functions */ template inline double Modulus( const T* __restrict__ i, const T* __restrict__ j ) noexcept { double S = 0; while ( i < j ) S += Abs( double( *i++ ) ); return S; } /*! * Computes the sum of the absolute values of the elements in a sequence [i,j) * using a numerically stable summation algorithm to minimize roundoff error. * * For empty sequences, this function returns zero. * * In the current PCL versions, this function implements the Kahan summation * algorithm to reduce roundoff error to the machine's floating point error. * * \ingroup statistical_functions */ template inline double StableModulus( const T* __restrict__ i, const T* __restrict__ j ) noexcept { double sum = 0; double eps = 0; while ( i < j ) { double y = Abs( double( *i++ ) ) - eps; double t = sum + y; eps = (t - sum) - y; sum = t; } return sum; } /*! * Returns the sum of the squares of the elements in a sequence [i,j). * * For empty sequences, this function returns zero. * * See the remarks made for the Sum() function, which are equally applicable in * this case. See StableSumOfSquares() for a (slow) numerically stable version * of this function. * * \ingroup statistical_functions */ template inline double SumOfSquares( const T* __restrict__ i, const T* __restrict__ j ) noexcept { double Q = 0; while ( i < j ) { double f = double( *i++ ); Q += f*f; } return Q; } /*! * Computes the sum of the squares of the elements in a sequence [i,j) using a * numerically stable summation algorithm to minimize roundoff error. * * For empty sequences, this function returns zero. * * In the current PCL versions, this function implements the Kahan summation * algorithm to reduce roundoff error to the machine's floating point error. * * \ingroup statistical_functions */ template inline double StableSumOfSquares( const T* __restrict__ i, const T* __restrict__ j ) noexcept { double sum = 0; double eps = 0; while ( i < j ) { double f = double( *i++ ); double y = f*f - eps; double t = sum + y; eps = (t - sum) - y; sum = t; } return sum; } /*! * Returns the arithmetic mean of a sequence [i,j). * * For empty sequences, this function returns zero. * * See the remarks made for the Sum() function, which are equally applicable in * this case. See StableMean() for a (slow) numerically stable version of this * function. * * \ingroup statistical_functions */ template inline double Mean( const T* __restrict__ i, const T* __restrict__ j ) noexcept { distance_type n = j - i; if ( n < 1 ) return 0; return Sum( i, j )/n; } /*! * Computes the arithmetic mean of a sequence [i,j) using a numerically stable * summation algorithm to minimize roundoff error. * * For empty sequences, this function returns zero. * * In the current PCL versions, this function implements the Kahan summation * algorithm to reduce roundoff error to the machine's floating point error. * * \ingroup statistical_functions */ template inline double StableMean( const T* __restrict__ i, const T* __restrict__ j ) noexcept { distance_type n = j - i; if ( n < 1 ) return 0; return StableSum( i, j )/n; } /*! * Returns the variance of a sequence [i,j) with respect to the specified * \a center value. * * For sequences of less than two elements, this function returns zero. * * This implementation uses a two-pass compensated summation algorithm to * minimize roundoff errors (see the references). * * \b References * * William H. Press et al., Numerical Recipes in C: The Art of Scientific * Computing, Second Edition (1997 reprint) Cambridge University Press, * page 613. * * \ingroup statistical_functions */ template inline double Variance( const T* __restrict__ i, const T* __restrict__ j, double center ) noexcept { distance_type n = j - i; if ( n < 2 ) return 0; double var = 0, eps = 0; do { double d = double( *i++ ) - center; var += d*d; eps += d; } while ( i < j ); return (var - eps*eps/n)/(n - 1); } /*! * Returns the variance from the mean of a sequence [i,j). * * For sequences of less than two elements, this function returns zero. * * This implementation uses a two-pass compensated summation algorithm to * minimize roundoff errors (see References). * * \b References * * William H. Press et al., Numerical Recipes in C: The Art of Scientific * Computing, Second Edition (1997 reprint) Cambridge University Press, * page 613. * * \ingroup statistical_functions */ template inline double Variance( const T* __restrict__ i, const T* __restrict__ j ) noexcept { distance_type n = j - i; if ( n < 2 ) return 0; double m = 0; for ( const T* f = i; f < j; ++f ) m += double( *f ); m /= n; double var = 0, eps = 0; do { double d = double( *i++ ) - m; var += d*d; eps += d; } while ( i < j ); return (var - eps*eps/n)/(n - 1); } /*! * Returns the standard deviation of a sequence [i,j) with respect to the * specified \a center value. * * For sequences of less than two elements, this function returns zero. * * \ingroup statistical_functions */ template inline double StdDev( const T* __restrict__ i, const T* __restrict__ j, double center ) noexcept { return Sqrt( Variance( i, j, center ) ); } /*! * Returns the standard deviation from the mean of a sequence [i,j). * * For sequences of less than two elements, this function returns zero. * * \ingroup statistical_functions */ template inline double StdDev( const T* __restrict__ i, const T* __restrict__ j ) noexcept { return Sqrt( Variance( i, j ) ); } /*! * Returns the median value of a sequence [i,j). * * For scalar data types the following algorithms are used: * * \li Hard-coded, fast selection networks for small sequences of 32 or less * elements. * * \li A quick selection algorithm for sequences of up to about 2M elements. * The actual limit has been determined empirically and can vary across PCL * versions. This single-threaded algorithm can use up to 16 MiB of additional * memory allocated dynamically (for 8-byte types such as \c double). * * \li A parallelized, fast histogram-based algorithm for sequences larger than * the limit described above. This algorithm has negligible additional memory * space requirements. * * For non-scalar data types, this function requires the following type * conversion operator publicly defined for the type T: * * \code T::operator double() const; \endcode * * This operator will be used to generate a temporary dynamic array of * \c double values with the length of the input sequence, which will be used * to compute the median with the algorithms enumerated above. * * \b References (selection networks) * * \li Knuth, D. E., The Art of Computer Programming, volume 3: * Sorting and Searching, Addison Wesley, 1973. * * \li Hillis, W. D., Co-evolving parasites improve simulated * evolution as an optimization procedure. Langton, C. et al. (Eds.), * Artificial Life II. Addison Wesley, 1992. * * \li Hugues Juille, Evolution of Non-Deterministic Incremental * Algorithms as a New Approach for Search in State Spaces, 1995 * * \b References (quick select algorithm) * * \li William H. Press et al., Numerical Recipes 3rd Edition: The Art of * Scientific Computing, Cambridge University Press, 2007, Section 8.5. * * \li Robert Sedgewick, Kevin Wayne, Algorithms, 4th Edition, * Addison-Wesley Professional, 2011, pp 345-347. * * \ingroup statistical_functions */ template inline double Median( const T* __restrict__ i, const T* __restrict__ j ) { distance_type n = j - i; if ( n < 1 ) return 0; if ( n == 1 ) return double( *i ); double* d = new double[ n ]; double* __restrict__ t = d; do *t++ = double( *i++ ); while ( i < j ); double m = double( *pcl::Select( d, t, n >> 1 ) ); if ( (n & 1) == 0 ) m = (m + double( *pcl::Select( d, t, (n >> 1)-1 ) ))/2; delete [] d; return m; } double PCL_FUNC Median( const unsigned char* __restrict__ i, const unsigned char* __restrict__ j ); double PCL_FUNC Median( const signed char* __restrict__ i, const signed char* __restrict__ j ); double PCL_FUNC Median( const wchar_t* __restrict__ i, const wchar_t* __restrict__ j ); double PCL_FUNC Median( const unsigned short* __restrict__ i, const unsigned short* __restrict__ j ); double PCL_FUNC Median( const signed short* __restrict__ i, const signed short* __restrict__ j ); double PCL_FUNC Median( const unsigned int* __restrict__ i, const unsigned int* __restrict__ j ); double PCL_FUNC Median( const signed int* __restrict__ i, const signed int* __restrict__ j ); double PCL_FUNC Median( const unsigned long* __restrict__ i, const unsigned long* __restrict__ j ); double PCL_FUNC Median( const signed long* __restrict__ i, const signed long* __restrict__ j ); double PCL_FUNC Median( const unsigned long long* __restrict__ i, const unsigned long long* __restrict__ j ); double PCL_FUNC Median( const signed long long* __restrict__ i, const signed long long* __restrict__ j ); double PCL_FUNC Median( const float* __restrict__ i, const float* __restrict__ j ); double PCL_FUNC Median( const double* __restrict__ i, const double* __restrict__ j ); double PCL_FUNC Median( const long double* __restrict__ i, const long double* __restrict__ j ); #define CMPXCHG( a, b ) \ if ( i[b] < i[a] ) pcl::Swap( i[a], i[b] ) #define MEAN( a, b ) \ (double( a ) + double( b ))/2 /*! * Returns the median value of a sequence [i,j), altering the existing order of * elements in the input sequence. * * This function is intended for sequences of non-scalar objects where the * order of elements is irrelevant, and hence generation of a working duplicate * is unnecessary. The following type conversion operator must be publicly * defined for the type T: * * \code T::operator double() const; \endcode * * The following algorithms are used: * * \li Hard-coded, fast selection networks for sequences of 9 or less elements. * * \li A quick selection algorithm for sequences larger than 9 elements. * * \note This is a \e destructive median calculation algorithm: it alters the * existing order of items in the input [i,j) sequence. * * \b References (selection networks) * * \li Knuth, D. E., The Art of Computer Programming, volume 3: * Sorting and Searching, Addison Wesley, 1973. * * \li Hillis, W. D., Co-evolving parasites improve simulated * evolution as an optimization procedure. Langton, C. et al. (Eds.), * Artificial Life II. Addison Wesley, 1992. * * \li Hugues Juille, Evolution of Non-Deterministic Incremental * Algorithms as a New Approach for Search in State Spaces, 1995 * * \b References (quick select algorithm) * * \li William H. Press et al., Numerical Recipes 3rd Edition: The Art of * Scientific Computing, Cambridge University Press, 2007, Section 8.5. * * \li Robert Sedgewick, Kevin Wayne, Algorithms, 4th Edition, * Addison-Wesley Professional, 2011, pp 345-347. * * \ingroup statistical_functions */ template inline double MedianDestructive( T* __restrict__ i, T* __restrict__ j ) noexcept { distance_type n = j - i; if ( n < 1 ) return 0; switch ( n ) { case 1: // !? return i[0]; case 2: return MEAN( i[0], i[1] ); case 3: CMPXCHG( 0, 1 ); CMPXCHG( 1, 2 ); return pcl::Max( i[0], i[1] ); case 4: CMPXCHG( 0, 1 ); CMPXCHG( 2, 3 ); CMPXCHG( 0, 2 ); CMPXCHG( 1, 3 ); return MEAN( i[1], i[2] ); case 5: CMPXCHG( 0, 1 ); CMPXCHG( 3, 4 ); CMPXCHG( 0, 3 ); CMPXCHG( 1, 4 ); CMPXCHG( 1, 2 ); CMPXCHG( 2, 3 ); return pcl::Max( i[1], i[2] ); case 6: CMPXCHG( 0, 1 ); CMPXCHG( 2, 3 ); CMPXCHG( 0, 2 ); CMPXCHG( 1, 3 ); CMPXCHG( 1, 2 ); CMPXCHG( 4, 5 ); CMPXCHG( 0, 4 ); CMPXCHG( 1, 5 ); CMPXCHG( 1, 4 ); CMPXCHG( 2, 4 ); CMPXCHG( 3, 5 ); CMPXCHG( 3, 4 ); return MEAN( i[2], i[3] ); case 7: CMPXCHG( 0, 5 ); CMPXCHG( 0, 3 ); CMPXCHG( 1, 6 ); CMPXCHG( 2, 4 ); CMPXCHG( 0, 1 ); CMPXCHG( 3, 5 ); CMPXCHG( 2, 6 ); CMPXCHG( 2, 3 ); CMPXCHG( 3, 6 ); CMPXCHG( 4, 5 ); CMPXCHG( 1, 4 ); CMPXCHG( 1, 3 ); return pcl::Min( i[3], i[4] ); case 8: CMPXCHG( 0, 4 ); CMPXCHG( 1, 5 ); CMPXCHG( 2, 6 ); CMPXCHG( 3, 7 ); CMPXCHG( 0, 2 ); CMPXCHG( 1, 3 ); CMPXCHG( 4, 6 ); CMPXCHG( 5, 7 ); CMPXCHG( 2, 4 ); CMPXCHG( 3, 5 ); CMPXCHG( 0, 1 ); CMPXCHG( 2, 3 ); CMPXCHG( 4, 5 ); CMPXCHG( 6, 7 ); CMPXCHG( 1, 4 ); CMPXCHG( 3, 6 ); return MEAN( i[3], i[4] ); case 9: CMPXCHG( 1, 2 ); CMPXCHG( 4, 5 ); CMPXCHG( 7, 8 ); CMPXCHG( 0, 1 ); CMPXCHG( 3, 4 ); CMPXCHG( 6, 7 ); CMPXCHG( 1, 2 ); CMPXCHG( 4, 5 ); CMPXCHG( 7, 8 ); CMPXCHG( 0, 3 ); CMPXCHG( 5, 8 ); CMPXCHG( 4, 7 ); CMPXCHG( 3, 6 ); CMPXCHG( 1, 4 ); CMPXCHG( 2, 5 ); CMPXCHG( 4, 7 ); CMPXCHG( 4, 2 ); CMPXCHG( 6, 4 ); return pcl::Min( i[2], i[4] ); default: { double m = double( *pcl::Select( i, j, n >> 1 ) ); if ( n & 1 ) return m; return MEAN( m, double( *pcl::Select( i, j, (n >> 1)-1 ) ) ); } } } #undef CMPXCHG #define CMPXCHG( a, b ) \ if ( p( i[b], i[a] ) ) pcl::Swap( i[a], i[b] ) /*! * Returns the median value of a sequence [i,j), altering the existing order of * elements in the input sequence. * * Element comparison is given by a binary predicate \a p such that p( a, b ) * is true for any pair a, b of elements such that a precedes b. * * We use fast, hard-coded selection networks for sequences of 9 or less * elements, and a quick selection algorithm for larger sets. * * See the documentation of MedianDestructive( T*, T* ) for more information * and references. * * \ingroup statistical_functions */ template inline double MedianDestructive( T* __restrict__ i, T* __restrict__ j, BP p ) noexcept { distance_type n = j - i; if ( n < 1 ) return 0; switch ( n ) { case 1: // !? return i[0]; case 2: return MEAN( i[0], i[1] ); case 3: CMPXCHG( 0, 1 ); CMPXCHG( 1, 2 ); return pcl::Max( i[0], i[1] ); case 4: CMPXCHG( 0, 1 ); CMPXCHG( 2, 3 ); CMPXCHG( 0, 2 ); CMPXCHG( 1, 3 ); return MEAN( i[1], i[2] ); case 5: CMPXCHG( 0, 1 ); CMPXCHG( 3, 4 ); CMPXCHG( 0, 3 ); CMPXCHG( 1, 4 ); CMPXCHG( 1, 2 ); CMPXCHG( 2, 3 ); return pcl::Max( i[1], i[2] ); case 6: CMPXCHG( 0, 1 ); CMPXCHG( 2, 3 ); CMPXCHG( 0, 2 ); CMPXCHG( 1, 3 ); CMPXCHG( 1, 2 ); CMPXCHG( 4, 5 ); CMPXCHG( 0, 4 ); CMPXCHG( 1, 5 ); CMPXCHG( 1, 4 ); CMPXCHG( 2, 4 ); CMPXCHG( 3, 5 ); CMPXCHG( 3, 4 ); return MEAN( i[2], i[3] ); case 7: CMPXCHG( 0, 5 ); CMPXCHG( 0, 3 ); CMPXCHG( 1, 6 ); CMPXCHG( 2, 4 ); CMPXCHG( 0, 1 ); CMPXCHG( 3, 5 ); CMPXCHG( 2, 6 ); CMPXCHG( 2, 3 ); CMPXCHG( 3, 6 ); CMPXCHG( 4, 5 ); CMPXCHG( 1, 4 ); CMPXCHG( 1, 3 ); return pcl::Min( i[3], i[4] ); case 8: CMPXCHG( 0, 4 ); CMPXCHG( 1, 5 ); CMPXCHG( 2, 6 ); CMPXCHG( 3, 7 ); CMPXCHG( 0, 2 ); CMPXCHG( 1, 3 ); CMPXCHG( 4, 6 ); CMPXCHG( 5, 7 ); CMPXCHG( 2, 4 ); CMPXCHG( 3, 5 ); CMPXCHG( 0, 1 ); CMPXCHG( 2, 3 ); CMPXCHG( 4, 5 ); CMPXCHG( 6, 7 ); CMPXCHG( 1, 4 ); CMPXCHG( 3, 6 ); return MEAN( i[3], i[4] ); case 9: CMPXCHG( 1, 2 ); CMPXCHG( 4, 5 ); CMPXCHG( 7, 8 ); CMPXCHG( 0, 1 ); CMPXCHG( 3, 4 ); CMPXCHG( 6, 7 ); CMPXCHG( 1, 2 ); CMPXCHG( 4, 5 ); CMPXCHG( 7, 8 ); CMPXCHG( 0, 3 ); CMPXCHG( 5, 8 ); CMPXCHG( 4, 7 ); CMPXCHG( 3, 6 ); CMPXCHG( 1, 4 ); CMPXCHG( 2, 5 ); CMPXCHG( 4, 7 ); CMPXCHG( 4, 2 ); CMPXCHG( 6, 4 ); return pcl::Min( i[2], i[4] ); default: { double m = double( *pcl::Select( i, j, n >> 1, p ) ); if ( n & 1 ) return m; return MEAN( m, double( *pcl::Select( i, j, (n >> 1)-1, p ) ) ); } } } #undef CMPXCHG #undef MEAN /*! * Returns the k-th order statistic of a sequence [i,j). * * For scalar data types the following algorithms are used: * * \li A quick selection algorithm for sequences of up to about 2M elements. * The actual limit has been determined empirically and can vary across PCL * versions. This single-threaded algorithm can use up to 16 MiB of additional * memory allocated dynamically (for 8-byte types such as \c double). * * \li A parallelized, fast histogram-based algorithm for sequences larger than * the limit described above. This algorithm has negligible additional memory * space requirements. * * For non-scalar data types, this function requires the following type * conversion operator publicly defined for the type T: * * \code T::operator double() const; \endcode * * This operator will be used to generate a temporary dynamic array of * \c double values with the length of the input sequence, which will be used * to compute the median with the quick selection algorithm. * * \b References (quick select algorithm) * * \li William H. Press et al., Numerical Recipes 3rd Edition: The Art of * Scientific Computing, Cambridge University Press, 2007, Section 8.5. * * \li Robert Sedgewick, Kevin Wayne, Algorithms, 4th Edition, * Addison-Wesley Professional, 2011, pp 345-347. * * \ingroup statistical_functions */ template inline double OrderStatistic( const T* __restrict__ i, const T* __restrict__ j, distance_type k ) { distance_type n = j - i; if ( n < 1 || k < 0 || k >= n ) return 0; if ( n == 1 ) return double( *i ); double* d = new double[ n ]; double* t = d; do *t++ = double( *i++ ); while ( i < j ); double s = *pcl::Select( d, t, k ); delete [] d; return s; } double PCL_FUNC OrderStatistic( const unsigned char* __restrict__ i, const unsigned char* __restrict__ j, distance_type k ); double PCL_FUNC OrderStatistic( const signed char* __restrict__ i, const signed char* __restrict__ j, distance_type k ); double PCL_FUNC OrderStatistic( const wchar_t* __restrict__ i, const wchar_t* __restrict__ j, distance_type k ); double PCL_FUNC OrderStatistic( const unsigned short* __restrict__ i, const unsigned short* __restrict__ j, distance_type k ); double PCL_FUNC OrderStatistic( const signed short* __restrict__ i, const signed short* __restrict__ j, distance_type k ); double PCL_FUNC OrderStatistic( const unsigned int* __restrict__ i, const unsigned int* __restrict__ j, distance_type k ); double PCL_FUNC OrderStatistic( const signed int* __restrict__ i, const signed int* __restrict__ j, distance_type k ); double PCL_FUNC OrderStatistic( const unsigned long* __restrict__ i, const unsigned long* __restrict__ j, distance_type k ); double PCL_FUNC OrderStatistic( const signed long* __restrict__ i, const signed long* __restrict__ j, distance_type k ); double PCL_FUNC OrderStatistic( const unsigned long long* __restrict__ i, const unsigned long long* __restrict__ j, distance_type k ); double PCL_FUNC OrderStatistic( const signed long long* __restrict__ i, const signed long long* __restrict__ j, distance_type k ); double PCL_FUNC OrderStatistic( const float* __restrict__ i, const float* __restrict__ j, distance_type k ); double PCL_FUNC OrderStatistic( const double* __restrict__ i, const double* __restrict__ j, distance_type k ); double PCL_FUNC OrderStatistic( const long double* __restrict__ i, const long double* __restrict__ j, distance_type k ); /*! * Returns the k-th order statistic of a sequence [i,j), altering the existing * order of elements in the input sequence. * * This function is intended for sequences of non-scalar objects where the * order of elements is irrelevant, and hence generation of a working duplicate * is unnecessary. The following type conversion operator must be publicly * defined for the type T: * * <\code> T::operator double() const; \endcode * * The quick selection algorithm is used to find the k-th element in the * ordered sequence. * * \note This is a \e destructive algorithm: it alters the existing order of * items in the input [i,j) sequence. * * \b References (quick select algorithm) * * \li William H. Press et al., Numerical Recipes 3rd Edition: The Art of * Scientific Computing, Cambridge University Press, 2007, Section 8.5. * * \li Robert Sedgewick, Kevin Wayne, Algorithms, 4th Edition, * Addison-Wesley Professional, 2011, pp 345-347. * * \ingroup statistical_functions */ template inline double OrderStatisticDestructive( T* __restrict__ i, T* __restrict__ j, distance_type k ) noexcept { distance_type n = j - i; if ( n < 1 || k < 0 || k >= n ) return 0; if ( n == 1 ) return double( *i ); return double( *pcl::Select( i, j, k ) ); } /*! * Returns the k-th order statistic of a sequence [i,j), altering the existing * order of elements in the input sequence. * * Element comparison is given by a binary predicate \a p such that p( a, b ) * is true for any pair a, b of elements such that a precedes b. * * See the documentation of OrderStatisticDestructive( T*, T*, distance_type ) * for more information and references. * * \ingroup statistical_functions */ template inline double OrderStatisticDestructive( const T* __restrict__ i, const T* __restrict__ j, distance_type k, BP p ) noexcept { distance_type n = j - i; if ( n < 1 || k < 0 || k >= n ) return 0; if ( n == 1 ) return double( *i ); return double( *pcl::Select( i, j, k, p ) ); } /*! * Computes the two-sided, asymmetric trimmed mean of a sequence [i,j). * * The returned value is the arithmetic mean of a sequence [I+l,J-h-1], where * [I,J) is the input sequence [i,j) sorted in ascending order. * * Let n = j-i be the length of the input sequence. For empty sequences * (n ≤ 0) or completely truncated sequences (l+h >= n), this function * returns zero. Otherwise the returned value is the arithmetic mean of the * nonrejected n-l-h elements in the sorted sequence, as described above. * * \ingroup statistical_functions */ template inline double TrimmedMean( const T* __restrict__ i, const T* __restrict__ j, distance_type l = 1, distance_type h = 1 ) { distance_type n = j - i; if ( n < 1 ) return 0; if ( l+h < 1 ) return Sum( i, j )/n; if ( l+h >= n ) return 0; for ( double s = 0, t0 = OrderStatistic( i, j, l ), t1 = OrderStatistic( i, j, n-h-1 ); ; ) { double x = double( *i ); if ( x >= t0 ) if ( x <= t1 ) s += x; if ( ++i == j ) return s/(n - l - h); } } /*! * Computes the two-sided, asymmetric trimmed mean of a sequence [i,j), * possibly altering the existing order of elements in the input sequence. * * The returned value is the arithmetic mean of a sequence [I+l,J-h-1], where * [I,J) represents the input sequence [i,j) sorted in ascending order. * * Let n = j-i be the length of the input sequence. For empty sequences * (n ≤ 0) or completely truncated sequences (l+h >= n), this function * returns zero. Otherwise the returned value is the arithmetic mean of the * nonrejected n-l-h elements in the sorted sequence, as described above. * * \note This is a \e destructive trimmed mean calculation algorithm: it may * alter the existing order of items in the input [i,j) sequence. * * \ingroup statistical_functions */ template inline double TrimmedMeanDestructive( T* __restrict__ i, T* __restrict__ j, distance_type l = 1, distance_type h = 1 ) noexcept { distance_type n = j - i; if ( n < 1 ) return 0; if ( l+h < 1 ) return Sum( i, j )/n; if ( l+h >= n ) return 0; for ( double s = 0, t0 = OrderStatisticDestructive( i, j, l ), t1 = OrderStatisticDestructive( i, j, n-h-1 ); ; ) { double x = double( *i ); if ( x >= t0 ) if ( x <= t1 ) s += x; if ( ++i == j ) return s/(n - l - h); } } /*! * Computes the two-sided, asymmetric trimmed mean of squares of a sequence * [i,j). * * The returned value is the arithmetic mean of squares of a sequence * [I+l,J-h-1], where [I,J) represents the input sequence [i,j) sorted in * ascending order. * * Let n = j-i be the length of the input sequence. For empty sequences * (n ≤ 0) or completely truncated sequences (l+h >= n), this function * returns zero. Otherwise the returned value is the arithmetic mean of the * squared nonrejected n-l-h elements in the sorted sequence, as described * above. * * \ingroup statistical_functions */ template inline double TrimmedMeanOfSquares( const T* __restrict__ i, const T* __restrict__ j, distance_type l = 1, distance_type h = 1 ) { distance_type n = j - i; if ( n < 1 ) return 0; if ( l+h < 1 ) return Sum( i, j )/n; if ( l+h >= n ) return 0; for ( double s = 0, t0 = OrderStatistic( i, j, l ), t1 = OrderStatistic( i, j, n-h-1 ); ; ) { double x = double( *i ); if ( x >= t0 ) if ( x <= t1 ) s += x*x; if ( ++i == j ) return s/(n - l - h); } } /*! * Computes the two-sided, asymmetric trimmed mean of squares of a sequence * [i,j), possibly altering the existing order of elements in the input * sequence. * * The returned value is the arithmetic mean of squares of a sequence * [I+l,J-h-1], where [I,J) represents the input sequence [i,j) sorted in * ascending order. * * Let n = j-i be the length of the input sequence. For empty sequences * (n ≤ 0) or completely truncated sequences (l+h >= n), this function * returns zero. Otherwise the returned value is the arithmetic mean of the * squared nonrejected n-l-h elements in the sorted sequence, as described * above. * * \note This is a \e destructive trimmed mean of squares calculation * algorithm: it may alter the existing order of items in the input [i,j) * sequence. * * \ingroup statistical_functions */ template inline double TrimmedMeanOfSquaresDestructive( T* __restrict__ i, T* __restrict__ j, distance_type l = 1, distance_type h = 1 ) noexcept { distance_type n = j - i; if ( n < 1 ) return 0; if ( l+h < 1 ) return Sum( i, j )/n; if ( l+h >= n ) return 0; for ( double s = 0, t0 = OrderStatisticDestructive( i, j, l ), t1 = OrderStatisticDestructive( i, j, n-h-1 ); ; ) { double x = double( *i ); if ( x >= t0 ) if ( x <= t1 ) s += x*x; if ( ++i == j ) return s/(n - l - h); } } /*! * Returns the average absolute deviation of the values in a sequence [i,j) * with respect to the specified \a center value. * * When the median of the sequence is used as the center value, this function * returns the average absolute deviation from the median, which is a * well-known estimator of dispersion. * * For sequences of less than two elements, this function returns zero. * * See the remarks made for the Sum() function, which are equally applicable in * this case. See StableAvgDev() for a (slow) numerically stable version of * this function. * * \note To make the average absolute deviation about the median consistent * with the standard deviation of a normal distribution, it must be * multiplied by the constant 1.2533. * * \ingroup statistical_functions */ template inline double AvgDev( const T* __restrict__ i, const T* __restrict__ j, double center ) noexcept { distance_type n = j - i; if ( n < 2 ) return 0; double d = 0; do d += Abs( double( *i++ ) - center ); while ( i < j ); return d/n; } /*! * Returns the average absolute deviation of the values in a sequence [i,j) * with respect to the specified \a center value, using a numerically stable * summation algorithm to minimize roundoff error. * * When the median of the sequence is used as the center value, this function * returns the average absolute deviation from the median, which is a * well-known estimator of dispersion. * * For sequences of less than two elements, this function returns zero. * * In the current PCL versions, this function implements the Kahan summation * algorithm to reduce roundoff error to the machine's floating point error. * * \note To make the average absolute deviation about the median consistent * with the standard deviation of a normal distribution, it must be * multiplied by the constant 1.2533. * * \ingroup statistical_functions */ template inline double StableAvgDev( const T* __restrict__ i, const T* __restrict__ j, double center ) noexcept { distance_type n = j - i; if ( n < 2 ) return 0; double sum = 0; double eps = 0; do { double y = Abs( double( *i++ ) - center ) - eps; double t = sum + y; eps = (t - sum) - y; sum = t; } while ( i < j ); return sum/n; } /*! * Returns the average absolute deviation from the median of the values in a * sequence [i,j). * * The average absolute deviation from the median is a well-known estimator of * dispersion. * * For sequences of less than two elements, this function returns zero. * * See the remarks made for the Sum() function, which are equally applicable in * this case. See StableAvgDev() for a (slow) numerically stable version of * this function. * * \note To make the average absolute deviation about the median consistent * with the standard deviation of a normal distribution, it must be * multiplied by the constant 1.2533. * * \ingroup statistical_functions */ template inline double AvgDev( const T* __restrict__ i, const T* __restrict__ j ) { distance_type n = j - i; if ( n < 2 ) return 0; double m = Median( i, j ); double d = 0; do d += Abs( double( *i++ ) - m ); while ( i < j ); return d/n; } /*! * Computes the average absolute deviation from the median of the values in a * sequence [i,j) using a numerically stable summation algorithm to minimize * roundoff error. * * The average absolute deviation from the median is a well-known estimator of * dispersion. * * For sequences of less than two elements, this function returns zero. * * In the current PCL versions, this function implements the Kahan summation * algorithm to reduce roundoff error to the machine's floating point error. * * \note To make the average absolute deviation about the median consistent * with the standard deviation of a normal distribution, it must be * multiplied by the constant 1.2533. * * \ingroup statistical_functions */ template inline double StableAvgDev( const T* __restrict__ i, const T* __restrict__ j ) { return pcl::StableAvgDev( i, j, pcl::Median( i, j ) ); } /*! * \struct TwoSidedEstimate * \brief Two-sided descriptive statistical estimate. * * This POD structure is returned by functions implementing two-sided scale * estimators. Given a sample X = {x_0,...,x_n-1} and a reference center value * m (typically, the median of X), a two-sided scale estimate is computed as * two separate components: A low estimate for all x in X such that * x ≤ m, and a high estimate for all x in X such that x > m. * * Two-sided scale estimates are important in normalization for accurate * outlier rejection and sample distribution characterization, especially for * skewed or asymmetric distributions. * * \ingroup statistical_functions * \sa TwoSidedAvgDev(), TwoSidedMAD(), TwoSidedBiweightMidvariance() */ struct TwoSidedEstimate { double low = 0; //!< Low estimate component. double high = 0; //!< High estimate component. /*! * Default constructor. Both components are initialized to zero. */ TwoSidedEstimate() = default; /*! * Copy constructor. */ TwoSidedEstimate( const TwoSidedEstimate& ) = default; /*! * Move constructor. */ TwoSidedEstimate( TwoSidedEstimate&& ) = default; /*! * Copy assignment operator. */ TwoSidedEstimate& operator =( const TwoSidedEstimate& ) = default; /*! * Move assignment operator. */ TwoSidedEstimate& operator =( TwoSidedEstimate&& ) = default; /*! * Constructor from separate low and high components. */ template TwoSidedEstimate( const T1& l, const T2& h ) : low( double( l ) ) , high( double( h ) ) { } /*! * Constructor from a unique component value \a x, which is assigned to both * the low and high estimate components. */ template TwoSidedEstimate( const T& x ) { low = high = double( x ); } /*! * Returns true iff this two-sided scale estimate is valid. A two-sided * scale estimate is valid if both the low and high components are finite, * positive and nonzero with respect to the machine epsilon for the type * \c double. */ bool IsValid() const noexcept { return IsFinite( low ) && low > std::numeric_limits::epsilon() && IsFinite( high ) && high > std::numeric_limits::epsilon(); } /*! * Returns the sum of the low and high estimate components. */ double Total() const noexcept { return low + high; } /*! * Returns the arithmetic mean of the low and high estimate components if * both are nonzero. Otherwise returns the maximum component. */ double Mean() const noexcept { if ( low != 0 ) { if ( high != 0 ) return (low + high)/2; return low; } return high; } /*! * Conversion to scalar. Equivalent to Mean(). */ explicit operator double() const noexcept { return Mean(); } /*! * Assignment-multiplication by a scalar. Returns a reference to this * object. */ TwoSidedEstimate& operator *=( double x ) noexcept { low *= x; high *= x; return *this; } /*! * Assignment-division by a scalar. Returns a reference to this object. */ TwoSidedEstimate& operator /=( double x ) noexcept { low /= x; high /= x; return *this; } /*! * Assignment-division by a two-sided estimate. Returns a reference to this * object. */ TwoSidedEstimate& operator /=( const TwoSidedEstimate& e ) noexcept { low /= e.low; high /= e.high; return *this; } /*! * Returns the result of multiplying this two-sided estimate by a scalar. */ TwoSidedEstimate operator *( double x ) const noexcept { return { low*x, high*x }; } /*! * Returns the result of dividing this two-sided estimate by a scalar. */ TwoSidedEstimate operator /( double x ) const noexcept { return { low/x, high/x }; } /*! * Returns the result of the component wise division of this two-sided * estimate by another two-sided estimate. */ TwoSidedEstimate operator /( const TwoSidedEstimate& e ) const noexcept { return { low/e.low, high/e.high }; } }; /*! * Returns the component wise square root of a two-sided estimate. * \ingroup statistical_functions */ inline TwoSidedEstimate Sqrt( const TwoSidedEstimate& e ) noexcept { return { Sqrt( e.low ), Sqrt( e.high ) }; } /*! * Returns the component wise exponent function of a two-sided estimate. * \ingroup statistical_functions */ template inline TwoSidedEstimate Pow( const TwoSidedEstimate& e, T x ) noexcept { double x_ = double( x ); return { Pow( e.low, x_ ), Pow( e.high, x_ ) }; } /*! * Returns the two-sided average absolute deviation of the values in a sequence * [i,j) with respect to the specified \a center value. * * When the median of the sequence is used as the center value, this function * returns the average absolute deviation from the median, which is a * well-known estimator of dispersion. * * For sequences of less than two elements, this function returns zero. * * See the remarks made for the Sum() function, which are equally applicable in * this case. See StableAvgDev() for a (slow) numerically stable version of * this function. * * \note To make the average absolute deviation about the median consistent * with the standard deviation of a normal distribution, it must be * multiplied by the constant 1.2533. * * \ingroup statistical_functions */ template inline TwoSidedEstimate TwoSidedAvgDev( const T* __restrict__ i, const T* __restrict__ j, double center ) noexcept { double dl = 0, dh = 0; distance_type nl = 0, nh = 0; while ( i < j ) { double x = double( *i++ ); if ( x <= center ) { dl += center - x; ++nl; } else { dh += x - center; ++nh; } } return { (nl > 1) ? dl/nl : 0.0, (nh > 1) ? dh/nh : 0.0 }; } /*! * Returns the two-sided average absolute deviation from the median of the * values in a sequence [i,j). * * The average absolute deviation from the median is a well-known estimator of * dispersion. * * For sequences of less than two elements, this function returns zero. * * See the remarks made for the Sum() function, which are equally applicable in * this case. See StableAvgDev() for a (slow) numerically stable version of * this function. * * \note To make the average absolute deviation about the median consistent * with the standard deviation of a normal distribution, it must be * multiplied by the constant 1.2533. * * \ingroup statistical_functions */ template inline TwoSidedEstimate TwoSidedAvgDev( const T* __restrict__ i, const T* __restrict__ j ) { return pcl::TwoSidedAvgDev( i, j, pcl::Median( i, j ) ); } /*! * Returns the median absolute deviation (MAD) of the values in a sequence * [i,j) with respect to the specified \a center value. * * The MAD is a well-known robust estimator of scale. * * For sequences of less than two elements, this function returns zero. * * \note To make the MAD estimator consistent with the standard deviation of * a normal distribution, its result must be multiplied by the constant 1.4826. * * \ingroup statistical_functions */ template inline double MAD( const T* __restrict__ i, const T* __restrict__ j, double center ) { distance_type n = j - i; if ( n < 2 ) return 0; double* d = new double[ n ]; double* p = d; do *p++ = Abs( double( *i++ ) - center ); while ( i < j ); double m = pcl::Median( d, d+n ); delete [] d; return m; } double PCL_FUNC MAD( const unsigned char* __restrict__ i, const unsigned char* __restrict__ j, double center ); double PCL_FUNC MAD( const signed char* __restrict__ i, const signed char* __restrict__ j, double center ); double PCL_FUNC MAD( const wchar_t* __restrict__ i, const wchar_t* __restrict__ j, double center ); double PCL_FUNC MAD( const unsigned short* __restrict__ i, const unsigned short* __restrict__ j, double center ); double PCL_FUNC MAD( const signed short* __restrict__ i, const signed short* __restrict__ j, double center ); double PCL_FUNC MAD( const unsigned int* __restrict__ i, const unsigned int* __restrict__ j, double center ); double PCL_FUNC MAD( const signed int* __restrict__ i, const signed int* __restrict__ j, double center ); double PCL_FUNC MAD( const unsigned long* __restrict__ i, const unsigned long* __restrict__ j, double center ); double PCL_FUNC MAD( const signed long* __restrict__ i, const signed long* __restrict__ j, double center ); double PCL_FUNC MAD( const unsigned long long* __restrict__ i, const unsigned long long* __restrict__ j, double center ); double PCL_FUNC MAD( const signed long long* __restrict__ i, const signed long long* __restrict__ j, double center ); double PCL_FUNC MAD( const float* __restrict__ i, const float* __restrict__ j, double center ); double PCL_FUNC MAD( const double* __restrict__ i, const double* __restrict__ j, double center ); double PCL_FUNC MAD( const long double* __restrict__ i, const long double* __restrict__ j, double center ); /*! * Returns the median absolute deviation from the median (MAD) for the values * in a sequence [i,j). * * The MAD is a well-known robust estimator of scale. * * For sequences of less than two elements, this function returns zero. * * \note To make the MAD estimator consistent with the standard deviation of * a normal distribution, its result must be multiplied by the constant 1.4826. * * \ingroup statistical_functions */ template inline double MAD( const T* __restrict__ i, const T* __restrict__ j ) { return pcl::MAD( i, j, pcl::Median( i, j ) ); } /*! * Returns the two-sided median absolute deviation (MAD) of the values in a * sequence [i,j) with respect to the specified \a center value. * * The MAD is a well-known robust estimator of scale. * * For sequences of less than two elements, this function returns zero. * * \note To make the MAD estimator consistent with the standard deviation of * a normal distribution, its result must be multiplied by the constant 1.4826. * * \ingroup statistical_functions */ template inline TwoSidedEstimate TwoSidedMAD( const T* __restrict__ i, const T* __restrict__ j, double center ) { distance_type n = j - i; if ( n < 2 ) return 0; double* d = new double[ n ]; double* __restrict__ p = d; double* __restrict__ q = d + n; do { double x = double( *i++ ); if ( x <= center ) *p++ = center - x; else *--q = x - center; } while( i < j ); double l = pcl::Median( d, p ); double h = pcl::Median( q, d+n ); delete [] d; return { l, h }; } TwoSidedEstimate PCL_FUNC TwoSidedMAD( const unsigned char* __restrict__ i, const unsigned char* __restrict__ j, double center ); TwoSidedEstimate PCL_FUNC TwoSidedMAD( const signed char* __restrict__ i, const signed char* __restrict__ j, double center ); TwoSidedEstimate PCL_FUNC TwoSidedMAD( const wchar_t* __restrict__ i, const wchar_t* __restrict__ j, double center ); TwoSidedEstimate PCL_FUNC TwoSidedMAD( const unsigned short* __restrict__ i, const unsigned short* __restrict__ j, double center ); TwoSidedEstimate PCL_FUNC TwoSidedMAD( const signed short* __restrict__ i, const signed short* __restrict__ j, double center ); TwoSidedEstimate PCL_FUNC TwoSidedMAD( const unsigned int* __restrict__ i, const unsigned int* __restrict__ j, double center ); TwoSidedEstimate PCL_FUNC TwoSidedMAD( const signed int* __restrict__ i, const signed int* __restrict__ j, double center ); TwoSidedEstimate PCL_FUNC TwoSidedMAD( const unsigned long* __restrict__ i, const unsigned long* __restrict__ j, double center ); TwoSidedEstimate PCL_FUNC TwoSidedMAD( const signed long* __restrict__ i, const signed long* __restrict__ j, double center ); TwoSidedEstimate PCL_FUNC TwoSidedMAD( const unsigned long long* __restrict__ i, const unsigned long long* __restrict__ j, double center ); TwoSidedEstimate PCL_FUNC TwoSidedMAD( const signed long long* __restrict__ i, const signed long long* __restrict__ j, double center ); TwoSidedEstimate PCL_FUNC TwoSidedMAD( const float* __restrict__ i, const float* __restrict__ j, double center ); TwoSidedEstimate PCL_FUNC TwoSidedMAD( const double* __restrict__ i, const double* __restrict__ j, double center ); TwoSidedEstimate PCL_FUNC TwoSidedMAD( const long double* __restrict__ i, const long double* __restrict__ j, double center ); /*! * Returns the two-sided median absolute deviation from the median (MAD) for * the values in a sequence [i,j). * * The MAD is a well-known robust estimator of scale. * * For sequences of less than two elements, this function returns zero. * * \note To make the MAD estimator consistent with the standard deviation of * a normal distribution, its result must be multiplied by the constant 1.4826. * * \ingroup statistical_functions */ template inline TwoSidedEstimate TwoSidedMAD( const T* __restrict__ i, const T* __restrict__ j ) { return pcl::TwoSidedMAD( i, j, pcl::Median( i, j ) ); } /*! * Returns the Sn scale estimator of Rousseeuw and Croux for a sequence [x,xn): * *
 * Sn = c * low_median( high_median( |x_i - x_j| ) )
 * 
* * where low_median() is the order statistic of rank (n + 1)/2, and * high_median() is the order statistic of rank n/2 + 1. n >= 2 is the number * of elements in the sequence: n = xn - x. * * This implementation is a direct C++ translation of the original FORTRAN * code by the authors (see References). The algorithm has O(n*log_2(n)) time * complexity and uses O(n) additional storage. * * The constant c = 1.1926 must be used to make the Sn estimator converge to * the standard deviation of a pure normal distribution. However, this * implementation does not apply it (it uses c=1 implicitly), for * consistency with other implementations of scale estimators. * * \b References * * P.J. Rousseeuw and C. Croux (1993), Alternatives to the Median Absolute * Deviation, Journal of the American Statistical Association, Vol. 88, * pp. 1273-1283. * * \note This is a \e destructive algorithm: it may alter the initial order of * items in the specified [x,xn) sequence. * * \ingroup statistical_functions */ template double Sn( T* __restrict__ x, T* __restrict__ xn ) { /* * N.B.: In the code below, lines commented with an asterisk (*) have been * modified with respect to the FORTRAN original to account for zero-based * array indices. */ distance_type n = xn - x; if ( n < 2 ) return 0; pcl::Sort( x, xn ); double* a2 = new double[ n ]; a2[0] = double( x[n >> 1] ) - double( x[0] ); // * distance_type nh = (n + 1) >> 1; for ( distance_type i = 2; i <= nh; ++i ) { distance_type nA = i-1; distance_type nB = n - i; distance_type diff = nB - nA; distance_type leftA = 1; distance_type leftB = 1; distance_type rightA = nB; distance_type Amin = (diff >> 1) + 1; distance_type Amax = (diff >> 1) + nA; while ( leftA < rightA ) { distance_type length = rightA - leftA + 1; distance_type even = (length & 1) == 0; distance_type half = (length - 1) >> 1; distance_type tryA = leftA + half; distance_type tryB = leftB + half; if ( tryA < Amin ) leftA = tryA + even; else { if ( tryA > Amax ) { rightA = tryA; leftB = tryB + even; } else { double medA = double( x[i-1] ) - double( x[i-2 - tryA + Amin] ); // * double medB = double( x[tryB + i-1] ) - double( x[i-1] ); // * if ( medA >= medB ) { rightA = tryA; leftB = tryB + even; } else leftA = tryA + even; } } } if ( leftA > Amax ) a2[i-1] = double( x[leftB + i-1] ) - double( x[i-1] ); // * else { double medA = double( x[i-1] ) - double( x[i-2 - leftA + Amin] ); // * double medB = double( x[leftB + i-1] ) - double( x[i-1] ); a2[i-1] = pcl::Min( medA, medB ); // * } } for ( distance_type i = nh + 1; i < n; ++i ) { distance_type nA = n - i; distance_type nB = i - 1; distance_type diff = nB - nA; distance_type leftA = 1; distance_type leftB = 1; distance_type rightA = nB; distance_type Amin = (diff >> 1) + 1; distance_type Amax = (diff >> 1) + nA; while ( leftA < rightA ) { distance_type length = rightA - leftA + 1; distance_type even = (length & 1) == 0; distance_type half = (length - 1) >> 1; distance_type tryA = leftA + half; distance_type tryB = leftB + half; if ( tryA < Amin) leftA = tryA + even; else { if ( tryA > Amax ) { rightA = tryA; leftB = tryB + even; } else { double medA = double( x[i + tryA - Amin] ) - double( x[i-1] ); // * double medB = double( x[i-1] ) - double( x[i-1 - tryB] ); // * if ( medA >= medB ) { rightA = tryA; leftB = tryB + even; } else leftA = tryA + even; } } } if ( leftA > Amax ) a2[i-1] = double( x[i-1] ) - double( x[i-1 - leftB] ); // * else { double medA = double( x[i + leftA - Amin] ) - double( x[i-1] ); // * double medB = double( x[i-1] ) - double( x[i-1 - leftB] ); // * a2[i-1] = pcl::Min( medA, medB ); // * } } a2[n-1] = double( x[n-1] ) - double( x[nh-1] ); // * /* * Correction for a finite sample */ double cn; switch ( n ) { case 2: cn = 0.743; break; case 3: cn = 1.851; break; case 4: cn = 0.954; break; case 5: cn = 1.351; break; case 6: cn = 0.993; break; case 7: cn = 1.198; break; case 8: cn = 1.005; break; case 9: cn = 1.131; break; default: cn = (n & 1) ? n/(n - 0.9) : 1.0; break; } double sn = cn * *pcl::Select( a2, a2+n, nh-1 ); delete [] a2; return sn; } /*! * \internal * Auxiliary routine for Qn(). * * Algorithm to compute the weighted high median in O(n) time. * * The weighted high median is defined as the smallest a[j] such that the sum * of the weights of all a[i] <= a[j] is strictly greater than half of the * total weight. */ inline double __pcl_whimed__( double* a, distance_type* iw, distance_type n, double* acand, distance_type* iwcand ) { distance_type wtotal = 0; for ( distance_type i = 0; i < n; ++i ) wtotal += iw[i]; for ( distance_type nn = n, wrest = 0; ; ) { double trial = *pcl::Select( a, a+nn, nn >> 1 ); // * distance_type wleft = 0; distance_type wmid = 0; distance_type wright = 0; for ( distance_type i = 0; i < nn; ++i ) if ( a[i] < trial ) wleft += iw[i]; else if ( a[i] > trial ) wright += iw[i]; else wmid += iw[i]; if ( 2*(wrest + wleft) > wtotal ) { distance_type kcand = 0; for ( distance_type i = 0; i < nn; ++i ) if ( a[i] < trial ) { acand[kcand] = a[i]; iwcand[kcand] = iw[i]; ++kcand; } nn = kcand; } else { if ( 2*(wrest + wleft + wmid) > wtotal ) return trial; distance_type kcand = 0; for ( distance_type i = 0; i < nn; ++i ) if ( a[i] > trial ) { acand[kcand] = a[i]; iwcand[kcand] = iw[i]; ++kcand; } nn = kcand; wrest += wleft + wmid; } for ( distance_type i = 0; i < nn; ++i ) { a[i] = acand[i]; iw[i] = iwcand[i]; } } } /*! * Returns the Qn scale estimator of Rousseeuw and Croux for a sequence [x,xn): * *
 * Qn = c * first_quartile( |x_i - x_j| : i < j )
 * 
* * where first_quartile() is the order statistic of rank (n + 1)/4. n >= 2 is * the number of elements in the sequence: n = xn - x. * * This implementation is a C++ translation of the original FORTRAN code by the * authors (see References). The algorithm has O(n*log_2(n)) time complexity * and the implementation requires about O(9*n) additional storage. * * The constant c = 2.2219 must be used to make the Qn estimator converge to * the standard deviation of a pure normal distribution. However, this * implementation does not apply it (it uses c=1 implicitly), for consistency * with other implementations of scale estimators. * * \b References * * P.J. Rousseeuw and C. Croux (1993), Alternatives to the Median Absolute * Deviation, Journal of the American Statistical Association, Vol. 88, * pp. 1273-1283. * * \note This is a \e destructive algorithm: it may alter the initial order of * items in the specified [x,xn) sequence. * * \ingroup statistical_functions */ template double Qn( T* __restrict__ x, T* __restrict__ xn ) { distance_type n = xn - x; if ( n < 2 ) return 0; double* y = new double[ n ]; double* work = new double[ n ]; double* acand = new double[ n ]; distance_type* iwcand = new distance_type[ n ]; distance_type* left = new distance_type[ n ]; distance_type* right = new distance_type[ n ]; distance_type* P = new distance_type[ n ]; distance_type* Q = new distance_type[ n ]; distance_type* weight = new distance_type[ n ]; distance_type h = (n >> 1) + 1; distance_type k = (h*(h - 1)) >> 1; for ( distance_type i = 0; i < n; ++i ) { y[i] = double( x[i] ); left[i] = n - i + 1; // * right[i] = (i <= h) ? n : n - i + h; // N.B. The original code is "right[i] = n" } pcl::Sort( y, y+n ); distance_type nL = (n*(n + 1)) >> 1; distance_type nR = n*n; distance_type knew = k + nL; bool found = false; double qn; while ( nR-nL > n ) { distance_type j = 0; // * for ( distance_type i = 1; i < n; ++i ) // * if ( left[i] <= right[i] ) { weight[j] = right[i] - left[i] + 1; work[j] = double( y[i] ) - y[n - left[i] - (weight[j] >> 1)]; ++j; } qn = __pcl_whimed__( work, weight, j, acand, iwcand ); for ( distance_type i = n-1, j = 0; i >= 0; --i ) // * { while ( j < n && double( y[i] ) - y[n-j-1] < qn ) ++j; P[i] = j; } for ( distance_type i = 0, j = n+1; i < n; ++i ) // * { while ( double( y[i] ) - y[n-j+1] > qn ) --j; Q[i] = j; } double sumP = 0; double sumQ = 0; for ( distance_type i = 0; i < n; ++i ) { sumP += P[i]; sumQ += Q[i] - 1; } if ( knew <= sumP ) { for ( distance_type i = 0; i < n; ++i ) right[i] = P[i]; nR = sumP; } else if ( knew > sumQ ) { for ( distance_type i = 0; i < n; ++i ) left[i] = Q[i]; nL = sumQ; } else { found = true; break; } } if ( !found ) { distance_type j = 0; for ( distance_type i = 1; i < n; ++i ) for ( distance_type jj = left[i]; jj <= right[i]; ++jj, ++j ) work[j] = double( y[i] ) - y[n-jj]; // * qn = *pcl::Select( work, work+j, knew-nL-1 ); // * } /* * Correction for a finite sample */ double dn; switch ( n ) { case 2: dn = 0.399; break; case 3: dn = 0.994; break; case 4: dn = 0.512; break; case 5: dn = 0.844; break; case 6: dn = 0.611; break; case 7: dn = 0.857; break; case 8: dn = 0.669; break; case 9: dn = 0.872; break; default: dn = (n & 1) ? n/(n + 1.4) : n/(n + 3.8); break; } qn *= dn; delete [] y; delete [] work; delete [] acand; delete [] iwcand; delete [] left; delete [] right; delete [] P; delete [] Q; delete [] weight; return qn; } /*! * Returns a biweight midvariance (BWMV) for the elements in a sequence [x,xn). * * \param x, xn Define a sequence of sample data points for which the BWMV * estimator will be calculated. * * \param center Reference center value. Normally, the median of the sample * should be used. * * \param sigma A reference estimate of dispersion. Normally, the median * absolute deviation from the median (MAD) of the sample should * be used. * * \param k Rejection limit in sigma units. The default value is k=9. * * \param reducedLength If true, reduce the sample size to exclude rejected * elements. This tends to approximate the true dispersion of * the data more accurately for relatively small samples, or * samples with large amounts of outliers. Note that this * departs from the standard definition of biweight midvariance, * where the total number of data items is used to scale the * variance estimate. If false, use the full sample size, * including rejected elements, which gives a standard biweight * midvariance estimate. * * The square root of the biweight midvariance is a robust estimator of scale. * It is an efficient estimator with respect to many statistical distributions * (about 87% Gaussian efficiency), and appears to have a breakdown point close * to 0.5 (the same as MAD). * * For sequences of less than two elements, this function returns zero. * * \note To make the BWMV estimator consistent with the standard deviation of * a normal distribution, its square root must be multiplied by the constant * 0.991. * * \b References * * Rand R. Wilcox (2017), Introduction to Robust Estimation and Hypothesis * Testing, 4th Edition, Elsevier Inc., Section 3.12.1. * * \ingroup statistical_functions */ template double BiweightMidvariance( const T* __restrict__ x, const T* __restrict__ xn, double center, double sigma, int k = 9, bool reducedLength = false ) noexcept { distance_type n = xn - x; if ( n < 2 ) return 0; double kd = k * sigma; if ( kd < 0 || 1 + kd == 1 ) return 0; double num = 0, den = 0; distance_type nr = 0; for ( ; x < xn; ++x ) { double xc = double( *x ) - center; double y = xc/kd; if ( Abs( y ) < 1 ) { double y2 = y*y; double y21 = 1 - y2; num += xc*xc * y21*y21*y21*y21; den += y21 * (1 - 5*y2); ++nr; } } den *= den; return (1 + den != 1) ? (reducedLength ? nr : n)*num/den : 0.0; } /*! * Returns a two-sided biweight midvariance (BWMV) for the elements in a * sequence [x,xn). * * \param x, xn Define a sequence of sample data points for which the * two-sided BWMV estimator will be calculated. * * \param center Reference center value. Normally, the median of the sample * should be used. * * \param sigma A reference two-sided estimate of dispersion. Normally, the * two-sided median absolute deviation from the median (MAD) of * the sample should be used. See the TwoSidedMAD() function. * * \param k Rejection limit in sigma units. The default value is k=9. * * \param reducedLength If true, reduce the sample size to exclude rejected * elements. Size reduction is performed separately for the low * and high halves of the data. This tends to approximate the * true dispersion of the data more accurately for relatively * small samples, or samples with large amounts of outliers. * Note that this departs from the standard definition of * biweight midvariance, where the total number of data items is * used to scale the variance estimate. If false, use the full * sample size, including rejected elements, which gives a * standard biweight midvariance estimate. * * See BiweightMidvariance() for more information and references. * * \ingroup statistical_functions */ template TwoSidedEstimate TwoSidedBiweightMidvariance( const T* __restrict__ x, const T* __restrict__ xn, double center, const TwoSidedEstimate& sigma, int k = 9, bool reducedLength = false ) noexcept { double kd0 = k * sigma.low; double kd1 = k * sigma.high; if ( kd0 < 0 || 1 + kd0 == 1 || kd1 < 0 || 1 + kd1 == 1 ) return 0; double num0 = 0, den0 = 0, num1 = 0, den1 = 0; size_type n0 = 0, n1 = 0, nr0 = 0, nr1 = 0; for ( ; x < xn; ++x ) { double xc = double( *x ) - center; bool low = xc <= 0; if ( low ) ++n0; else ++n1; double y = xc/(low ? kd0 : kd1); if ( pcl::Abs( y ) < 1 ) { double y2 = y*y; double y21 = 1 - y2; double num = xc*xc * y21*y21*y21*y21; double den = y21 * (1 - 5*y2); if ( low ) { num0 += num; den0 += den; ++nr0; } else { num1 += num; den1 += den; ++nr1; } } } den0 *= den0; den1 *= den1; return { (n0 >= 2 && 1 + den0 != 1) ? (reducedLength ? nr0 : n0)*num0/den0 : 0.0, (n1 >= 2 && 1 + den1 != 1) ? (reducedLength ? nr1 : n1)*num1/den1 : 0.0 }; } /*! * Returns a percentage bend midvariance (PBMV) for the elements in a sequence * [x,xn). * * \param x, xn Define a sequence of sample data points for which the PBWV * estimator will be calculated. * * \param center Reference center value. Normally, the median of the sample * should be used. * * \param beta Rejection parameter in the [0,0.5] range. Higher values * improve robustness to outliers (i.e., increase the breakdown * point of the estimator) at the expense of a lower efficiency. * The default value is beta=0.2. * * The square root of the percentage bend midvariance is a robust estimator of * scale. With the default beta=0.2, its Gaussian efficiency is 67%. With * beta=0.1, its efficiency is 85% but its breakdown is only 0.1. * * For sequences of less than two elements, this function returns zero. * * \b References * * Rand R. Wilcox (2012), Introduction to Robust Estimation and Hypothesis * Testing, 3rd Edition, Elsevier Inc., Section 3.12.3. * * \ingroup statistical_functions */ template double BendMidvariance( const T* __restrict__ x, const T* __restrict__ xn, double center, double beta = 0.2 ) { distance_type n = xn - x; if ( n < 2 ) return 0; beta = Range( beta, 0.0, 0.5 ); distance_type m = Floor( (1 - beta)*n + 0.5 ); double* w = new double[ n ]; for ( distance_type i = 0; i < n; ++i ) w[i] = Abs( double( x[i] ) - center ); double wb = *pcl::Select( w, w+n, m ); delete [] w; if ( 1 + wb == 1 ) return 0; double num = 0; distance_type den = 0; for ( ; x < xn; ++x ) { double y = (double( *x ) - center)/wb; double f = Max( -1.0, Min( 1.0, y ) ); num += f*f; if ( Abs( y ) < 1 ) ++den; } den *= den; return (1 + den != 1) ? n*wb*wb*num/den : 0.0; } // ---------------------------------------------------------------------------- /*! * \defgroup special_functions Special Functions */ /*! * Evaluation of the regularized incomplete beta function I_x( a, b ). * * \param a,b The a and b parameters of the beta function being evaluated. * * \param x Function evaluation point. Must be in the range [0,1]. * * \param eps Relative accuracy of the returned function evaluation. The * default value is 1.0e-8. * * This implementation is adapted from original code by Lewis Van Winkle, * released under zlib license: * *
 * https://codeplea.com/incomplete-beta-function-c
 * https://github.com/codeplea/incbeta
 * 
* * Copyright (c) 2016, 2017 Lewis Van Winkle * * \ingroup special_functions */ inline double IncompleteBeta( double a, double b, double x, double eps = 1.0e-8 ) noexcept { if ( x < 0 || x > 1 ) return std::numeric_limits::infinity(); /* * The continued fraction converges nicely for x < (a+1)/(a+b+2) */ if ( x > (a + 1)/(a + b + 2) ) return 1 - IncompleteBeta( b, a, 1 - x ); // Use the fact that beta is symmetric /* * Find the first part before the continued fraction. */ double lbeta_ab = lgamma( a ) + lgamma( b ) - lgamma( a + b ); double front = Exp( Ln( x )*a + Ln( 1 - x )*b - lbeta_ab )/a; /* * Use Lentz's algorithm to evaluate the continued fraction. */ const double tiny = 1.0e-30; double f = 1, c = 1, d = 0; for ( int i = 0; i <= 200; ++i ) { int m = i >> 1; double numerator; if ( i & 1 ) numerator = -((a + m)*(a + b + m)*x)/((a + 2*m)*(a + 2*m + 1)); // Odd term else if ( i > 0 ) numerator = (m*(b - m)*x)/((a + 2*m - 1)*(a + 2*m)); // Even term else numerator = 1; // First numerator is 1.0 /* * Do an iteration of Lentz's algorithm. */ d = 1 + numerator*d; if ( Abs( d ) < tiny ) d = tiny; d = 1/d; c = 1 + numerator/c; if ( Abs( c ) < tiny ) c = tiny; double cd = c*d; f *= cd; if ( Abs( 1 - cd ) < eps ) return front*(f - 1); } // Needed more loops, did not converge. return std::numeric_limits::infinity(); } // ---------------------------------------------------------------------------- /*! * The error function: erf( \a x ). * \ingroup mathematical_functions */ template inline constexpr T Erf( T x ) noexcept { return std::erf( x ); } /*! * The inverse error function: erf^-1( \a x ). * * Code adapted from erfinv implementation by Lakshay Garg: * * https://github.com/lakshayg/erfinv * * Copyright (c) 2017-2019 Lakshay Garg * Licensed under MIT license. * * \ingroup mathematical_functions */ template inline constexpr T ErfInv( T x ) noexcept { if ( x < -1 || x > 1 ) return std::numeric_limits::quiet_NaN(); if ( x == 1 ) return std::numeric_limits::infinity(); if ( x == -1 ) return -std::numeric_limits::infinity(); const long double A0 = 1.1975323115670912564578e0L; const long double A1 = 4.7072688112383978012285e1L; const long double A2 = 6.9706266534389598238465e2L; const long double A3 = 4.8548868893843886794648e3L; const long double A4 = 1.6235862515167575384252e4L; const long double A5 = 2.3782041382114385731252e4L; const long double A6 = 1.1819493347062294404278e4L; const long double A7 = 8.8709406962545514830200e2L; const long double B0 = 1.0000000000000000000e0L; const long double B1 = 4.2313330701600911252e1L; const long double B2 = 6.8718700749205790830e2L; const long double B3 = 5.3941960214247511077e3L; const long double B4 = 2.1213794301586595867e4L; const long double B5 = 3.9307895800092710610e4L; const long double B6 = 2.8729085735721942674e4L; const long double B7 = 5.2264952788528545610e3L; const long double C0 = 1.42343711074968357734e0L; const long double C1 = 4.63033784615654529590e0L; const long double C2 = 5.76949722146069140550e0L; const long double C3 = 3.64784832476320460504e0L; const long double C4 = 1.27045825245236838258e0L; const long double C5 = 2.41780725177450611770e-1L; const long double C6 = 2.27238449892691845833e-2L; const long double C7 = 7.74545014278341407640e-4L; const long double D0 = 1.4142135623730950488016887e0L; const long double D1 = 2.9036514445419946173133295e0L; const long double D2 = 2.3707661626024532365971225e0L; const long double D3 = 9.7547832001787427186894837e-1L; const long double D4 = 2.0945065210512749128288442e-1L; const long double D5 = 2.1494160384252876777097297e-2L; const long double D6 = 7.7441459065157709165577218e-4L; const long double D7 = 1.4859850019840355905497876e-9L; const long double E0 = 6.65790464350110377720e0L; const long double E1 = 5.46378491116411436990e0L; const long double E2 = 1.78482653991729133580e0L; const long double E3 = 2.96560571828504891230e-1L; const long double E4 = 2.65321895265761230930e-2L; const long double E5 = 1.24266094738807843860e-3L; const long double E6 = 2.71155556874348757815e-5L; const long double E7 = 2.01033439929228813265e-7L; const long double F0 = 1.414213562373095048801689e0L; const long double F1 = 8.482908416595164588112026e-1L; const long double F2 = 1.936480946950659106176712e-1L; const long double F3 = 2.103693768272068968719679e-2L; const long double F4 = 1.112800997078859844711555e-3L; const long double F5 = 2.611088405080593625138020e-5L; const long double F6 = 2.010321207683943062279931e-7L; const long double F7 = 2.891024605872965461538222e-15L; long double abs_x = Abs( x ); if ( abs_x <= 0.85L ) { long double r = 0.180625L - 0.25L * x*x; long double num = (((((((A7*r + A6)*r + A5)*r + A4)*r + A3)*r + A2)*r + A1)*r + A0); long double den = (((((((B7*r + B6)*r + B5)*r + B4)*r + B3)*r + B2)*r + B1)*r + B0); return T( x * num/den ); } long double r = Sqrt( Ln2() - Ln( 1 - abs_x ) ); long double num = 0, den = 0; if ( r <= 5 ) { r = r - 1.6L; num = (((((((C7*r + C6)*r + C5)*r + C4)*r + C3)*r + C2)*r + C1)*r + C0); den = (((((((D7*r + D6)*r + D5)*r + D4)*r + D3)*r + D2)*r + D1)*r + D0); } else { r = r - 5.0L; num = (((((((E7*r + E6)*r + E5)*r + E4)*r + E3)*r + E2)*r + E1)*r + E0); den = (((((((F7*r + F6)*r + F5)*r + F4)*r + F3)*r + F2)*r + F1)*r + F0); } return T( std::copysign( num/den, x ) ); } // ---------------------------------------------------------------------------- /*! * \defgroup hash_functions Non-Cryptographic Hash Functions */ /*! * Computes a 64-bit non-cryptographic hash function. * * \param data Address of the first byte of the input data block. * * \param size Length in bytes of the input data block. * * \param seed Optional seed value for initialization of the hash function. * If \a seed is zero or is not specified, the seed will be set * equal to the length of the data block. * * Returns a 64-bit hash value computed from the input data block. * *
 * Test vector: "The quick brown fox jumps over the lazy dog"
 * Hash64 checksum = 9a11f5e9468d7425
 *
 * Test vector: "" (empty string)\n
 * Hash64 checksum = ef46db3751d8e999
 * 
* * This function implements the xxHash algorithm by Yann Collet. Our code is an * adaptation of the original code by the author: * *
 * https://github.com/Cyan4973/xxHash
 * 
* * Copyright (C) 2012-2014, Yann Collet. \n * The original code has been released under the BSD 2-Clause License: * *
 * http://www.opensource.org/licenses/bsd-license.php
 * 
* * \ingroup hash_functions */ inline uint64 Hash64( const void* data, size_type size, uint64 seed = 0 ) noexcept { #define PRIME64_1 11400714785074694791ULL #define PRIME64_2 14029467366897019727ULL #define PRIME64_3 1609587929392839161ULL #define PRIME64_4 9650029242287828579ULL #define PRIME64_5 2870177450012600261ULL const uint8* p = (const uint8*)data; const uint8* end = p + size; uint64 h64; if ( seed == 0 ) seed = size; if ( size >= 32 ) { const uint8* limit = end - 32; uint64 v1 = seed + PRIME64_1 + PRIME64_2; uint64 v2 = seed + PRIME64_2; uint64 v3 = seed + 0; uint64 v4 = seed - PRIME64_1; do { v1 += *(uint64*)p * PRIME64_2; p += 8; v1 = RotL( v1, 31 ); v1 *= PRIME64_1; v2 += *(uint64*)p * PRIME64_2; p += 8; v2 = RotL( v2, 31 ); v2 *= PRIME64_1; v3 += *(uint64*)p * PRIME64_2; p += 8; v3 = RotL( v3, 31 ); v3 *= PRIME64_1; v4 += *(uint64*)p * PRIME64_2; p += 8; v4 = RotL( v4, 31 ); v4 *= PRIME64_1; } while ( p <= limit ); h64 = RotL( v1, 1 ) + RotL( v2, 7 ) + RotL( v3, 12 ) + RotL( v4, 18 ); v1 *= PRIME64_2; v1 = RotL( v1, 31 ); v1 *= PRIME64_1; h64 ^= v1; h64 = h64 * PRIME64_1 + PRIME64_4; v2 *= PRIME64_2; v2 = RotL( v2, 31 ); v2 *= PRIME64_1; h64 ^= v2; h64 = h64 * PRIME64_1 + PRIME64_4; v3 *= PRIME64_2; v3 = RotL( v3, 31 ); v3 *= PRIME64_1; h64 ^= v3; h64 = h64 * PRIME64_1 + PRIME64_4; v4 *= PRIME64_2; v4 = RotL( v4, 31 ); v4 *= PRIME64_1; h64 ^= v4; h64 = h64 * PRIME64_1 + PRIME64_4; } else { h64 = seed + PRIME64_5; } h64 += size; while ( p+8 <= end ) { uint64 k1 = *(uint64*)p; k1 *= PRIME64_2; k1 = RotL( k1, 31 ); k1 *= PRIME64_1; h64 ^= k1; h64 = RotL( h64, 27 ) * PRIME64_1 + PRIME64_4; p += 8; } if ( p+4 <= end ) { h64 ^= (uint64)(*(uint32*)p) * PRIME64_1; h64 = RotL( h64, 23 ) * PRIME64_2 + PRIME64_3; p += 4; } while ( p < end ) { h64 ^= *p * PRIME64_5; h64 = RotL( h64, 11 ) * PRIME64_1; ++p; } h64 ^= h64 >> 33; h64 *= PRIME64_2; h64 ^= h64 >> 29; h64 *= PRIME64_3; h64 ^= h64 >> 32; return h64; #undef PRIME64_1 #undef PRIME64_2 #undef PRIME64_3 #undef PRIME64_4 #undef PRIME64_5 } /*! * Computes a 32-bit non-cryptographic hash function. * * \param data Address of the first byte of the input data block. * * \param size Length in bytes of the input data block. * * \param seed Optional seed value for initialization of the hash function. * If \a seed is zero or is not specified, the seed will be set * equal to the length of the data block. * * Returns a 32-bit hash value computed from the input data block. * *
 * Test vector: "The quick brown fox jumps over the lazy dog"\n
 * Hash32 checksum = 752cd1b8
 *
 * Test vector: "" (empty string)\n
 * Hash32 checksum = 2cc5d05
 * 
* * This function implements the xxHash algorithm by Yann Collet. Our code is an * adaptation of the original code by the author: * *
 * https://github.com/Cyan4973/xxHash
 * 
* * Copyright (C) 2012-2014, Yann Collet. \n * The original code has been released under the BSD 2-Clause License: * *
 * http://www.opensource.org/licenses/bsd-license.php
 * 
* * \ingroup hash_functions */ inline uint32 Hash32( const void* data, size_type size, uint32 seed = 0 ) noexcept { #define PRIME32_1 2654435761U #define PRIME32_2 2246822519U #define PRIME32_3 3266489917U #define PRIME32_4 668265263U #define PRIME32_5 374761393U const uint8* p = (const uint8*)data; const uint8* end = p + size; uint32 h32; if ( seed == 0 ) seed = uint32( size ); if ( size >= 16 ) { const uint8* limit = end - 16; uint32 v1 = seed + PRIME32_1 + PRIME32_2; uint32 v2 = seed + PRIME32_2; uint32 v3 = seed + 0; uint32 v4 = seed - PRIME32_1; do { v1 += *(uint32*)p * PRIME32_2; v1 = RotL( v1, 13 ); v1 *= PRIME32_1; p += 4; v2 += *(uint32*)p * PRIME32_2; v2 = RotL( v2, 13 ); v2 *= PRIME32_1; p += 4; v3 += *(uint32*)p * PRIME32_2; v3 = RotL( v3, 13 ); v3 *= PRIME32_1; p += 4; v4 += *(uint32*)p * PRIME32_2; v4 = RotL( v4, 13 ); v4 *= PRIME32_1; p += 4; } while ( p <= limit ); h32 = RotL( v1, 1 ) + RotL( v2, 7 ) + RotL( v3, 12 ) + RotL( v4, 18 ); } else { h32 = seed + PRIME32_5; } h32 += (uint32)size; while ( p+4 <= end ) { h32 += *(uint32*)p * PRIME32_3; h32 = RotL( h32, 17 ) * PRIME32_4 ; p+=4; } while ( p < end ) { h32 += *p * PRIME32_5; h32 = RotL( h32, 11 ) * PRIME32_1 ; ++p; } h32 ^= h32 >> 15; h32 *= PRIME32_2; h32 ^= h32 >> 13; h32 *= PRIME32_3; h32 ^= h32 >> 16; return h32; #undef PRIME32_1 #undef PRIME32_2 #undef PRIME32_3 #undef PRIME32_4 #undef PRIME32_5 } // ---------------------------------------------------------------------------- } // pcl #endif // __PCL_Math_h // ---------------------------------------------------------------------------- // EOF pcl/Math.h - Released 2022-03-12T18:59:29Z