4997 lines
145 KiB
C++
4997 lines
145 KiB
C++
// ____ ______ __
|
|
// / __ \ / ____// /
|
|
// / /_/ // / / /
|
|
// / ____// /___ / /___ 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 ≥ 0.
|
|
*
|
|
* A static lookup table is used to speed up for \a n <= 127.
|
|
*
|
|
* \ingroup mathematical_functions
|
|
*/
|
|
inline double Factorial( int n ) noexcept
|
|
{
|
|
PCL_PRECONDITION( n >= 0 )
|
|
if ( n <= FactorialCache::s_cacheSize )
|
|
return FactorialCache::s_lut[n];
|
|
double x = FactorialCache::s_lut[FactorialCache::s_cacheSize];
|
|
for ( int m = FactorialCache::s_cacheSize; ++m <= n; )
|
|
x *= m;
|
|
return x;
|
|
}
|
|
|
|
/*!
|
|
* The natural logarithm of the factorial of \a n ≥ 0.
|
|
*
|
|
* For \a n <= 127 computes the natural logarithm of the factorial function
|
|
* directly. For \a n > 127 computes a series approximation, so that the
|
|
* function won't overflow even for very large arguments.
|
|
*
|
|
* \ingroup mathematical_functions
|
|
*/
|
|
inline double LnFactorial( int n ) noexcept
|
|
{
|
|
PCL_PRECONDITION( n >= 0 )
|
|
if ( n <= FactorialCache::s_cacheSize )
|
|
return Ln( FactorialCache::s_lut[n] );
|
|
double x = n + 1;
|
|
// return (x - 0.5)*Ln( x ) - x + 0.5*Ln( TwoPi() ) + 1/12/x - 1/(360*x*x*x);
|
|
return (x - 0.5)*Ln( x ) - x + 0.91893853320467267 + 1/12/x - 1/(360*x*x*x);
|
|
}
|
|
|
|
/*!
|
|
* \class Fact
|
|
* \brief Factorial function.
|
|
*
|
|
* We use a static lookup table to speed up for \a n <= 127.
|
|
*
|
|
* Example of use:
|
|
*
|
|
* \code double factorialOfEight = Fact<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 ≥ 0.
|
|
*/
|
|
T operator()( int n ) const noexcept
|
|
{
|
|
PCL_PRECONDITION( n >= 0 )
|
|
if ( n <= s_cacheSize )
|
|
return T( s_lut[n] );
|
|
double x = s_lut[s_cacheSize];
|
|
for ( int m = s_cacheSize; ++m <= n; )
|
|
x *= m;
|
|
return T( x );
|
|
}
|
|
|
|
/*!
|
|
* Returns the natural logarithm of the factorial of \a n ≥ 0. For
|
|
* \a n <= 127 computes the natural logarithm of the factorial function
|
|
* directly. For \a n > 127 computes a series approximation, so that the
|
|
* function won't overflow even for very large arguments.
|
|
*/
|
|
T Ln( int n ) const noexcept
|
|
{
|
|
PCL_PRECONDITION( n >= 0 )
|
|
if ( n <= s_cacheSize )
|
|
return T( pcl::Ln( s_lut[n] ) );
|
|
double x = n + 1;
|
|
// return T( (x - 0.5)*pcl::Ln( x ) - x + 0.5*pcl::Ln( TwoPi() ) + 1/12/x - 1/(360*x*x*x) );
|
|
return T( (x - 0.5)*pcl::Ln( x ) - x + 0.91893853320467267 + 1/12/x - 1/(360*x*x*x) );
|
|
}
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/*!
|
|
* Natural (base e) logarithm of two.
|
|
* \ingroup mathematical_functions
|
|
*/
|
|
inline constexpr long double Ln2() noexcept
|
|
{
|
|
return (long double)( 0.6931471805599453094172321214581766e+00L );
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/*!
|
|
* Base 10 Logarithm of x.
|
|
* \ingroup mathematical_functions
|
|
*/
|
|
template <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 ≤ 0
|
|
* 0 if x = 0
|
|
* +1 if x ≥ 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 ≤ 0
|
|
* ' ' if x = 0
|
|
* '+' if x ≥ 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 < 0
|
|
* sign = +1 iff d ≥ 0
|
|
* 0 ≤ s1
|
|
* 0 ≤ s2 < 60
|
|
* 0 ≤ s3 < 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 ≤ 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 ≤ 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 ≤ 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 ≤ 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 ≤ 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
|