//     ____   ______ __
//    / __ \ / ____// /
//   / /_/ // /    / /
//  / ____// /___ / /___   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 <pcl/Defs.h>
#include <pcl/Diagnostics.h>

#include <pcl/Memory.h>
#include <pcl/Selection.h>
#include <pcl/Sort.h>
#include <pcl/Utility.h>

#include <cmath>
#include <cstdlib>
#include <limits>

#ifdef _MSC_VER
#  include <intrin.h> // for __cpuid()
#endif

#if defined( __x86_64__ ) || defined( _M_X64 ) || defined( __PCL_MACOSX )
#  define __PCL_HAVE_SSE2  1
#  include <emmintrin.h>
#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 <QtWidgets/QtWidgets>
#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:
 *
 * <pre>
 *  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
 * </pre>
 *
 * \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:
 *
 * <pre>
 * +1 if \a x is <em>positive infinity</em>.
 * -1 if \a x is <em>negative infinity</em>.
 *  0 if \a x is either NaN or a finite value.
 * </pre>
 *
 * \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:
 *
 * <pre>
 * +1 if \a x is <em>positive infinity</em>.
 * -1 if \a x is <em>negative infinity</em>.
 *  0 if \a x is either NaN or a finite value.
 * </pre>
 *
 * \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 <typename T> 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 <typename T> 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 <typename T> 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 <typename T> 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 <typename T> inline constexpr T ArcTan( T x ) noexcept
{
   return std::atan( x );
}

// ----------------------------------------------------------------------------

/*!
 * Arctangent of y/x, result in the proper quadrant.
 * \ingroup mathematical_functions
 */
template <typename T> 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 <typename T> inline T ArcTan2Pi( T y, T x ) noexcept
{
   T r = ArcTan( y, x );
   if ( r < 0 )
      r = static_cast<T>( r + TwoPi() );
   return r;
}

// ----------------------------------------------------------------------------

/*!
 * The ceil function: lowest integer >= x.
 * \ingroup mathematical_functions
 */
template <typename T> inline constexpr T Ceil( T x ) noexcept
{
   return std::ceil( x );
}

// ----------------------------------------------------------------------------

/*!
 * Cosine function.
 * \ingroup mathematical_functions
 */
template <typename T> inline constexpr T Cos( T x ) noexcept
{
   return std::cos( x );
}

// ----------------------------------------------------------------------------

/*!
 * Hyperbolic Cosine function.
 * \ingroup mathematical_functions
 */
template <typename T> 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 <typename T> inline constexpr T Cotan( T x ) noexcept
{
   return T( 1 )/std::tan( x );
}

// ----------------------------------------------------------------------------

/*!
 * Conversion from radians to degrees.
 * \ingroup mathematical_functions
 */
template <typename T> inline constexpr T Deg( T x ) noexcept
{
   return static_cast<T>( 0.572957795130823208767981548141051700441964e+02L * x );
}

// ----------------------------------------------------------------------------

/*!
 * The exponential function e**x.
 * \ingroup mathematical_functions
 */
template <typename T> inline constexpr T Exp( T x ) noexcept
{
   return std::exp( x );
}

// ----------------------------------------------------------------------------

/*!
 * The floor function: highest integer <= x.
 * \ingroup mathematical_functions
 */
template <typename T> 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 <typename T> 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 <typename T> inline void Frexp( T x, T& m, int& p ) noexcept
{
   m = std::frexp( x, &p );
}

// ----------------------------------------------------------------------------

/*!
 * Haversine function:
 *
 * <tt>Hav( x ) = (1 - Cos( x ))/2</tt>
 *
 * The haversine is useful to work with tiny angles.
 *
 * \ingroup mathematical_functions
 */
template <typename T> inline constexpr T Hav( T x ) noexcept
{
   return (1 - Cos( x ))/2;
}

// ----------------------------------------------------------------------------

/*!
 * Calculates m * 2**p.
 * \ingroup mathematical_functions
 */
template <typename T> 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 <typename T> 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 &ge; 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 &ge; 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<double>()( 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 <typename T> struct PCL_CLASS Fact : public FactorialCache
{
   /*!
    * Returns the factorial of \a n &ge; 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 &ge; 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 <typename T> 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 <typename T> 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 <typename T> 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 <typename T> 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:
 *
 * <pre>
 * y = c[0] + c[1]*x + c[2]*x**2 + ... + c[n]*x**n
 * </pre>
 *
 * 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 <typename T, typename C> 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:
 *
 * <pre>
 * y = c[0] + c[1]*x + c[2]*x**2 + ... + c[n]*x**n
 * </pre>
 *
 * The specified coefficients initializer list \a c must not be empty;
 * otherwise this function invokes undefined behavior.
 *
 * \ingroup mathematical_functions
 */
template <typename T> inline T Poly( T x, std::initializer_list<T> c ) noexcept
{
   PCL_PRECONDITION( c.size() > 0 )
   return Poly( x, c.begin(), int( c.size() )-1 );
}

// ----------------------------------------------------------------------------

/*!
 * Sign function:
 *
 * <pre>
 * -1 if x &le; 0
 *  0 if x = 0
 * +1 if x &ge; 0
 * </pre>
 *
 * \ingroup mathematical_functions
 */
template <typename T> inline constexpr int Sign( T x ) noexcept
{
   return (x < 0) ? -1 : ((x > 0) ? +1 : 0);
}

// ----------------------------------------------------------------------------

/*!
 * Sign character:
 *
 * <pre>
 * '-' if x &le; 0
 * ' ' if x = 0
 * '+' if x &ge; 0
 * </pre>
 *
 * \ingroup mathematical_functions
 */
template <typename T> inline constexpr char SignChar( T x ) noexcept
{
   return (x < 0) ? '-' : ((x > 0) ? '+' : ' ');
}

// ----------------------------------------------------------------------------

/*!
 * Sine function
 * \ingroup mathematical_functions
 */
template <typename T> inline constexpr T Sin( T x ) noexcept
{
   return std::sin( x );
}

// ----------------------------------------------------------------------------

/*!
 * Hyperbolic Sine function.
 * \ingroup mathematical_functions
 */
template <typename T> 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 <typename T> 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 <typename T> inline void Split( T x, T& i, T& f ) noexcept
{
   f = std::modf( x, &i );
}

// ----------------------------------------------------------------------------

/*!
 * Square root function.
 * \ingroup mathematical_functions
 */
template <typename T> inline constexpr T Sqrt( T x ) noexcept
{
   return sqrt( x );
}

// ----------------------------------------------------------------------------

/*!
 * Tangent function.
 * \ingroup mathematical_functions
 */
template <typename T> inline constexpr T Tan( T x ) noexcept
{
   return std::tan( x );
}

// ----------------------------------------------------------------------------

/*!
 * Hyperbolic Tangent function.
 * \ingroup mathematical_functions
 */
template <typename T> inline constexpr T Tanh( T x ) noexcept
{
   return std::tanh( x );
}

// ----------------------------------------------------------------------------

/*!
 * Truncated integer part of \a x.
 * \ingroup mathematical_functions
 */
template <typename T> 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 <typename T> 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 <typename T> 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 <typename T> 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 <typename T> 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 <tt>Pow10I\<T\>()( y )</tt> when x == 10 and y is an integer
 * \li Use <tt>PowI( x, y )</tt> when x != 10 and y is an integer
 * \li Use <tt>Pow10( y )</tt> when x == 10 and y is not an integer
 *
 * Otherwise, you can also use: <tt>Pow2( y*Log2( x ) )</tt>
 *
 * \ingroup mathematical_functions
 */
template <typename T> 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<double>()( 5 ); // x = 10^5 \endcode
 *
 * \ingroup mathematical_functions
 */
template <typename T> 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<T>( 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 <typename T> inline T Pow10( T x ) noexcept
{
   int i = TruncInt( x );
   return (i == x) ? Pow10I<T>()( 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 <typename T> inline T RotL( T x, uint32 n ) noexcept
{
   static_assert( std::is_unsigned<T>::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 <typename T> inline T RotR( T x, uint32 n ) noexcept
{
   static_assert( std::is_unsigned<T>::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:
 *
 * <pre>
 * RoundInt( 0.5 ) -> 0
 * RoundInt( 1.5 ) -> 2
 * RoundInt( 2.5 ) -> 2
 * RoundInt( 3.5 ) -> 4
 * </pre>
 *
 * By contrast, arithmetic rounding rounds a perfect half to the nearest digit,
 * either odd or even. For example:
 *
 * <pre>
 * RoundIntArithmetic( 0.5 ) -> 1
 * RoundIntArithmetic( 1.5 ) -> 2
 * RoundIntArithmetic( 2.5 ) -> 3
 * RoundIntArithmetic( 3.5 ) -> 4
 * </pre>
 *
 * 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 <typename T> 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 <typename T> 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 <typename T> 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:
 *
 * <pre>
 * RoundIntArithmetic( 0.5 ) -> 1
 * RoundIntArithmetic( 1.5 ) -> 2
 * RoundIntArithmetic( 2.5 ) -> 3
 * RoundIntArithmetic( 3.5 ) -> 4
 * </pre>
 *
 * 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 <typename T> 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:
 *
 * <pre>
 * RoundIntArithmetic( 0.5 ) -> 1
 * RoundIntArithmetic( 1.5 ) -> 2
 * RoundIntArithmetic( 2.5 ) -> 3
 * RoundIntArithmetic( 3.5 ) -> 4
 * </pre>
 *
 * 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 <typename T> inline T Round( T x, int n ) noexcept
{
   PCL_PRECONDITION( n >= 0 )
   T p = Pow10I<T>()( n ); return Round( p*x )/p;
}

// ----------------------------------------------------------------------------

/*!
 * The exponential function 2**x.
 * \ingroup mathematical_functions
 */
template <typename T> 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<float>()( -2 ); // x = 1/4 \endcode
 *
 * \ingroup mathematical_functions
 */
template <typename T> 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 <typename T> 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 <typename T> inline T PowI4( T x ) noexcept
{
   x *= x; return x*x;
}

/*!
 * Returns \a x raised to the 6th power.
 * \ingroup mathematical_functions
 */
template <typename T> inline T PowI6( T x ) noexcept
{
   x *= x*x; return x*x;
}

/*!
 * Returns \a x raised to the 8th power.
 * \ingroup mathematical_functions
 */
template <typename T> 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 <typename T> 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 <typename T> inline T PowI12( T x ) noexcept
{
   x *= x*x*x*x*x; return x*x;
}

// ----------------------------------------------------------------------------

/*!
 * Inverse hyperbolic sine function.
 *
 * <tt>ArcSinh( x ) = Ln( x + Sqrt( 1 + x**2 ) )</tt>
 *
 * \ingroup mathematical_functions
 */
template <typename T> 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.
 *
 * <tt>ArcCosh( x ) = 2*Ln( Sqrt( (x + 1)/2 ) + Sqrt( (x - 1)/2 ) )</tt>
 *
 * \ingroup mathematical_functions
 */
template <typename T> 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.
 *
 * <tt>ArcTanh( x ) = (Ln( 1 + x ) - Ln( 1 - x ))/2</tt>
 *
 * \ingroup mathematical_functions
 */
template <typename T> 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:
 *
 * <tt>ArcHav( x ) = 2*ArcSin( Sqrt( x ) )</tt>
 *
 * The haversine is useful to work with tiny angles.
 *
 * \ingroup mathematical_functions
 */
template <typename T> inline constexpr T ArcHav( T x ) noexcept
{
   return 2*ArcSin( Sqrt( x ) );
}

// ----------------------------------------------------------------------------

/*!
 * Conversion from degrees to radians.
 * \ingroup mathematical_functions
 */
template <typename T> inline constexpr T Rad( T x ) noexcept
{
   return static_cast<T>( 0.174532925199432957692369076848861272222e-01L * x );
}

// ----------------------------------------------------------------------------

/*!
 * Conversion from radians to arcminutes.
 * \ingroup mathematical_functions
 */
template <typename T> inline constexpr T RadMin( T x ) noexcept
{
   return Deg( x )*60;
}

// ----------------------------------------------------------------------------

/*!
 * Conversion from radians to arcseconds.
 * \ingroup mathematical_functions
 */
template <typename T> inline constexpr T RadSec( T x ) noexcept
{
   return Deg( x )*3600;
}

// ----------------------------------------------------------------------------

/*!
 * Conversion from arcminutes to radians.
 * \ingroup mathematical_functions
 */
template <typename T> inline constexpr T MinRad( T x ) noexcept
{
   return Rad( x/60 );
}

// ----------------------------------------------------------------------------

/*!
 * Conversion from arcseconds to radians.
 * \ingroup mathematical_functions
 */
template <typename T> inline constexpr T SecRad( T x ) noexcept
{
   return Rad( x/3600 );
}

/*!
 * Conversion from arcseconds to radians (a synonym for SecRad()).
 * \ingroup mathematical_functions
 */
template <typename T> inline constexpr T AsRad( T x ) noexcept
{
   return SecRad( x );
}

// ----------------------------------------------------------------------------

/*!
 * Conversion from milliarcseconds (mas) to radians.
 * \ingroup mathematical_functions
 */
template <typename T> inline constexpr T MasRad( T x ) noexcept
{
   return Rad( x/3600000 );
}

// ----------------------------------------------------------------------------

/*!
 * Conversion from microarcseconds (uas) to radians.
 * \ingroup mathematical_functions
 */
template <typename T> 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 <typename T> inline constexpr T ModPi( T x ) noexcept
{
   x = Mod( x + static_cast<T>( Pi() ), static_cast<T>( TwoPi() ) ) - static_cast<T>( Pi() );
   return (x < -static_cast<T>( Pi() )) ? x + static_cast<T>( TwoPi() ) : x;
}

// ----------------------------------------------------------------------------

/*!
 * An angle in radians reduced to the (-2pi,+2pi) range, that is, the remainder
 * of x/(2*pi).
 * \ingroup mathematical_functions
 */
template <typename T> inline constexpr T Mod2Pi( T x ) noexcept
{
   return Mod( x, static_cast<T>( TwoPi() ) );
}

// ----------------------------------------------------------------------------

/*!
 * An angle in radians normalized to the [0,2pi) range.
 * \ingroup mathematical_functions
 */
template <typename T> inline constexpr T Norm2Pi( T x ) noexcept
{
   return ((x = Mod2Pi( x )) < 0) ? x + static_cast<T>( 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 <typename T, typename T1, typename T2>
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 <typename T1, typename T2>
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 <typename T1, typename T2>
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 <typename T1, typename T2>
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 <typename T, typename T1, typename T2>
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 <typename T, typename P, typename N> 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:
 *
 * <pre>
 * N = sum( abs( x )^p )^(1/p)
 * </pre>
 *
 * for all x in [i,j).
 *
 * \ingroup mathematical_functions
 * \sa L1Norm(), L2Norm()
 */
template <typename T, typename P> inline T Norm( const T* i, const T* j, const P& p ) noexcept
{
   return __pcl_norm__( i, j, p, (T*)( 0 ) );
}

template <typename P> inline double Norm( const float* i, const float* j, const P& p ) noexcept
{
   return __pcl_norm__( i, j, p, (double*)( 0 ) );
}
template <typename P> inline double Norm( const int* i, const int* j, const P& p ) noexcept
{
   return __pcl_norm__( i, j, p, (double*)( 0 ) );
}
template <typename P> inline double Norm( const unsigned* i, const unsigned* j, const P& p ) noexcept
{
   return __pcl_norm__( i, j, p, (double*)( 0 ) );
}
template <typename P> inline double Norm( const int8* i, const int8* j, const P& p ) noexcept
{
   return __pcl_norm__( i, j, p, (double*)( 0 ) );
}
template <typename P> inline double Norm( const uint8* i, const uint8* j, const P& p ) noexcept
{
   return __pcl_norm__( i, j, p, (double*)( 0 ) );
}
template <typename P> inline double Norm( const int16* i, const int16* j, const P& p ) noexcept
{
   return __pcl_norm__( i, j, p, (double*)( 0 ) );
}
template <typename P> inline double Norm( const uint16* i, const uint16* j, const P& p ) noexcept
{
   return __pcl_norm__( i, j, p, (double*)( 0 ) );
}
template <typename P> inline double Norm( const int64* i, const int64* j, const P& p ) noexcept
{
   return __pcl_norm__( i, j, p, (double*)( 0 ) );
}
template <typename P> inline double Norm( const uint64* i, const uint64* j, const P& p ) noexcept
{
   return __pcl_norm__( i, j, p, (double*)( 0 ) );
}

// ----------------------------------------------------------------------------

template <typename T, typename N> 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 <typename T> 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 <typename T, typename N> 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 <typename T> 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 <typename T> 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), <em>Astronomical Algorithms</em>, 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), <em>Astronomical Algorithms</em>, 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:
 *
 * <pre>
 * d = sign * (s1 + (s2 + s3/60)/60)
 * </pre>
 *
 * with the following constraints:
 *
 * <pre>
 * sign = -1 iff d &lt; 0
 * sign = +1 iff d &ge; 0
 * 0 &le; s1
 * 0 &le; s2 &lt; 60
 * 0 &le; s3 &lt; 60
 * </pre>
 *
 * \ingroup mathematical_functions
 */
template <typename S1, typename S2, typename S3, typename D>
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:
 *
 * <pre>
 * ((sign < 0) ? -1 : +1)*(Abs( s1 ) + (s2 + s3/60)/60);
 * </pre>
 *
 * \ingroup mathematical_functions
 */
template <typename S1, typename S2, typename S3>
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 <typename T> 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 <typename T> 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 <typename T> 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 <typename T> 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 <typename T> 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 <typename T> 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 <typename T> 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 <typename T> 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., <em>Numerical Recipes in C: The Art of Scientific
 * Computing, Second Edition</em> (1997 reprint) Cambridge University Press,
 * page 613.
 *
 * \ingroup statistical_functions
 */
template <typename T> 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., <em>Numerical Recipes in C: The Art of Scientific
 * Computing, Second Edition</em> (1997 reprint) Cambridge University Press,
 * page 613.
 *
 * \ingroup statistical_functions
 */
template <typename T> 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 <typename T> 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 <typename T> 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., <em>The Art of Computer Programming, volume 3:
 * Sorting and Searching,</em> Addison Wesley, 1973.
 *
 * \li Hillis, W. D., <em>Co-evolving parasites improve simulated
 * evolution as an optimization procedure.</em> Langton, C. et al. (Eds.),
 * Artificial Life II. Addison Wesley, 1992.
 *
 * \li Hugues Juille, <em>Evolution of Non-Deterministic Incremental
 * Algorithms as a New Approach for Search in State Spaces,</em> 1995
 *
 * \b References (quick select algorithm)
 *
 * \li William H. Press et al., <em>Numerical Recipes 3rd Edition: The Art of
 * Scientific Computing,</em> Cambridge University Press, 2007, Section 8.5.
 *
 * \li Robert Sedgewick, Kevin Wayne, <em>Algorithms, 4th Edition,</em>
 * Addison-Wesley Professional, 2011, pp 345-347.
 *
 * \ingroup statistical_functions
 */
template <class T> 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., <em>The Art of Computer Programming, volume 3:
 * Sorting and Searching,</em> Addison Wesley, 1973.
 *
 * \li Hillis, W. D., <em>Co-evolving parasites improve simulated
 * evolution as an optimization procedure.</em> Langton, C. et al. (Eds.),
 * Artificial Life II. Addison Wesley, 1992.
 *
 * \li Hugues Juille, <em>Evolution of Non-Deterministic Incremental
 * Algorithms as a New Approach for Search in State Spaces,</em> 1995
 *
 * \b References (quick select algorithm)
 *
 * \li William H. Press et al., <em>Numerical Recipes 3rd Edition: The Art of
 * Scientific Computing,</em> Cambridge University Press, 2007, Section 8.5.
 *
 * \li Robert Sedgewick, Kevin Wayne, <em>Algorithms, 4th Edition,</em>
 * Addison-Wesley Professional, 2011, pp 345-347.
 *
 * \ingroup statistical_functions
 */
template <typename T> 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 <typename T, class BP> 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., <em>Numerical Recipes 3rd Edition: The Art of
 * Scientific Computing,</em> Cambridge University Press, 2007, Section 8.5.
 *
 * \li Robert Sedgewick, Kevin Wayne, <em>Algorithms, 4th Edition,</em>
 * Addison-Wesley Professional, 2011, pp 345-347.
 *
 * \ingroup statistical_functions
 */
template <typename T> 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., <em>Numerical Recipes 3rd Edition: The Art of
 * Scientific Computing,</em> Cambridge University Press, 2007, Section 8.5.
 *
 * \li Robert Sedgewick, Kevin Wayne, <em>Algorithms, 4th Edition,</em>
 * Addison-Wesley Professional, 2011, pp 345-347.
 *
 * \ingroup statistical_functions
 */
template <typename T> 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 <typename T, class BP> 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 &le; 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 <typename T> 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 &le; 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 <typename T> 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 &le; 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 <typename T> 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 &le; 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 <typename T> 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 <typename T> 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 <typename T> 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 <typename T> 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 <typename T> 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 <em>low estimate</em> for all x in X such that
 * x &le; m, and a <em>high estimate</em> 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 <typename T1, typename T2>
   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 <typename T>
   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<double>::epsilon()
          && IsFinite( high ) && high > std::numeric_limits<double>::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 <typename T> 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 <typename T> 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 <typename T> 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 <typename T> 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 <typename T> 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 <typename T> 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 <typename T> 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):
 *
 * <pre>
 * Sn = c * low_median( high_median( |x_i - x_j| ) )
 * </pre>
 *
 * 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), <em>Alternatives to the Median Absolute
 * Deviation,</em> 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 <typename T> 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):
 *
 * <pre>
 * Qn = c * first_quartile( |x_i - x_j| : i < j )
 * </pre>
 *
 * 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), <em>Alternatives to the Median Absolute
 * Deviation,</em> 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 <typename T> 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), <em>Introduction to Robust Estimation and Hypothesis
 * Testing, 4th Edition</em>, Elsevier Inc., Section 3.12.1.
 *
 * \ingroup statistical_functions
 */
template <typename T>
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 <typename T>
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), <em>Introduction to Robust Estimation and Hypothesis
 * Testing, 3rd Edition</em>, Elsevier Inc., Section 3.12.3.
 *
 * \ingroup statistical_functions
 */
template <typename T>
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:
 *
 * <pre>
 * https://codeplea.com/incomplete-beta-function-c
 * https://github.com/codeplea/incbeta
 * </pre>
 *
 * 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<double>::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<double>::infinity();
}

// ----------------------------------------------------------------------------

/*!
 * The error function: erf( \a x ).
 * \ingroup mathematical_functions
 */
template <typename T> 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 <typename T> inline constexpr T ErfInv( T x ) noexcept
{
  if ( x < -1 || x > 1 )
    return std::numeric_limits<T>::quiet_NaN();
  if ( x == 1 )
    return std::numeric_limits<T>::infinity();
  if ( x == -1 )
    return -std::numeric_limits<T>::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.
 *
 * <pre>
 * Test vector: "The quick brown fox jumps over the lazy dog"
 * Hash64 checksum = 9a11f5e9468d7425
 *
 * Test vector: "" (empty string)\n
 * Hash64 checksum = ef46db3751d8e999
 * </pre>
 *
 * This function implements the xxHash algorithm by Yann Collet. Our code is an
 * adaptation of the original code by the author:
 *
 * <pre>
 * https://github.com/Cyan4973/xxHash
 * </pre>
 *
 * Copyright (C) 2012-2014, Yann Collet. \n
 * The original code has been released under the BSD 2-Clause License:
 *
 * <pre>
 * http://www.opensource.org/licenses/bsd-license.php
 * </pre>
 *
 * \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.
 *
 * <pre>
 * Test vector: "The quick brown fox jumps over the lazy dog"\n
 * Hash32 checksum = 752cd1b8
 *
 * Test vector: "" (empty string)\n
 * Hash32 checksum = 2cc5d05
 * </pre>
 *
 * This function implements the xxHash algorithm by Yann Collet. Our code is an
 * adaptation of the original code by the author:
 *
 * <pre>
 * https://github.com/Cyan4973/xxHash
 * </pre>
 *
 * Copyright (C) 2012-2014, Yann Collet. \n
 * The original code has been released under the BSD 2-Clause License:
 *
 * <pre>
 * http://www.opensource.org/licenses/bsd-license.php
 * </pre>
 *
 * \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
