mirror of
				https://github.com/saitohirga/WSJT-X.git
				synced 2025-10-31 13:10:19 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			162 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			162 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| [section:lgamma Log Gamma]
 | |
| 
 | |
| [h4 Synopsis]
 | |
| 
 | |
| ``
 | |
| #include <boost/math/special_functions/gamma.hpp>
 | |
| ``
 | |
| 
 | |
|    namespace boost{ namespace math{
 | |
|    
 | |
|    template <class T>
 | |
|    ``__sf_result`` lgamma(T z);
 | |
|    
 | |
|    template <class T, class ``__Policy``>
 | |
|    ``__sf_result`` lgamma(T z, const ``__Policy``&);
 | |
|    
 | |
|    template <class T>
 | |
|    ``__sf_result`` lgamma(T z, int* sign);
 | |
|    
 | |
|    template <class T, class ``__Policy``>
 | |
|    ``__sf_result`` lgamma(T z, int* sign, const ``__Policy``&);
 | |
|    
 | |
|    }} // namespaces
 | |
| 
 | |
| [h4 Description]
 | |
| 
 | |
| The [@http://en.wikipedia.org/wiki/Gamma_function lgamma function] is defined by:
 | |
| 
 | |
| [equation lgamm1]
 | |
| 
 | |
| The second form of the function takes a pointer to an integer,
 | |
| which if non-null is set on output to the sign of tgamma(z).
 | |
| 
 | |
| [optional_policy]
 | |
| 
 | |
| [graph lgamma]
 | |
| 
 | |
| There are effectively two versions of this function internally: a fully
 | |
| generic version that is slow, but reasonably accurate, and a much more
 | |
| efficient approximation that is used where the number of digits in the significand
 | |
| of T correspond to a certain __lanczos.  In practice, any built-in
 | |
| floating-point type you will encounter has an appropriate __lanczos
 | |
| defined for it.  It is also possible, given enough machine time, to generate
 | |
| further __lanczos's using the program libs/math/tools/lanczos_generator.cpp.
 | |
| 
 | |
| The return type of these functions is computed using the __arg_promotion_rules:
 | |
| the result is of type `double` if T is an integer type, or type T otherwise.
 | |
| 
 | |
| [h4 Accuracy]
 | |
| 
 | |
| The following table shows the peak errors (in units of epsilon) 
 | |
| found on various platforms
 | |
| with various floating point types, along with comparisons to 
 | |
| various other libraries. Unless otherwise specified any
 | |
| floating point type that is narrower than the one shown will have
 | |
| __zero_error.
 | |
| 
 | |
| Note that while the relative errors near the positive roots of lgamma
 | |
| are very low, the lgamma function has an infinite number of irrational
 | |
| roots for negative arguments: very close to these negative roots only
 | |
| a low absolute error can be guaranteed.
 | |
| 
 | |
| [table_lgamma]
 | |
| 
 | |
| [h4 Testing]
 | |
| 
 | |
| The main tests for this function involve comparisons against the logs of 
 | |
| the factorials which can be independently calculated to very high accuracy.
 | |
| 
 | |
| Random tests in key problem areas are also used.
 | |
| 
 | |
| [h4 Implementation]
 | |
| 
 | |
| The generic version of this function is implemented using Sterling's approximation
 | |
| for large arguments:
 | |
| 
 | |
| [equation gamma6]
 | |
| 
 | |
| For small arguments, the logarithm of tgamma is used.
 | |
| 
 | |
| For negative /z/ the logarithm version of the 
 | |
| reflection formula is used:
 | |
| 
 | |
| [equation lgamm3]
 | |
| 
 | |
| For types of known precision, the __lanczos is used, a traits class 
 | |
| `boost::math::lanczos::lanczos_traits` maps type T to an appropriate
 | |
| approximation.  The logarithmic version of the __lanczos is:
 | |
| 
 | |
| [equation lgamm4]
 | |
| 
 | |
| Where L[sub e,g][space] is the Lanczos sum, scaled by e[super g].
 | |
| 
 | |
| As before the reflection formula is used for /z < 0/.
 | |
| 
 | |
| When z is very near 1 or 2, then the logarithmic version of the __lanczos
 | |
| suffers very badly from cancellation error: indeed for values sufficiently
 | |
| close to 1 or 2, arbitrarily large relative errors can be obtained (even though
 | |
| the absolute error is tiny).  
 | |
| 
 | |
| For types with up to 113 bits of precision
 | |
| (up to and including 128-bit long doubles), root-preserving 
 | |
| rational approximations [jm_rationals] are used
 | |
| over the intervals [1,2] and [2,3].  Over the interval [2,3] the approximation
 | |
| form used is:
 | |
| 
 | |
|    lgamma(z) = (z-2)(z+1)(Y + R(z-2));
 | |
|    
 | |
| Where Y is a constant, and R(z-2) is the rational approximation: optimised
 | |
| so that it's absolute error is tiny compared to Y.  In addition 
 | |
| small values of z greater
 | |
| than 3 can handled by argument reduction using the recurrence relation:
 | |
| 
 | |
|    lgamma(z+1) = log(z) + lgamma(z);
 | |
|    
 | |
| Over the interval [1,2] two approximations have to be used, one for small z uses:
 | |
| 
 | |
|    lgamma(z) = (z-1)(z-2)(Y + R(z-1));
 | |
|    
 | |
| Once again Y is a constant, and R(z-1) is optimised for low absolute error
 | |
| compared to Y.  For z > 1.5 the above form wouldn't converge to a 
 | |
| minimax solution but this similar form does:
 | |
| 
 | |
|    lgamma(z) = (2-z)(1-z)(Y + R(2-z));
 | |
|    
 | |
| Finally for z < 1 the recurrence relation can be used to move to z > 1:
 | |
| 
 | |
|    lgamma(z) = lgamma(z+1) - log(z);
 | |
|    
 | |
| Note that while this involves a subtraction, it appears not
 | |
| to suffer from cancellation error: as z decreases from 1 
 | |
| the `-log(z)` term grows positive much more
 | |
| rapidly than the `lgamma(z+1)` term becomes negative.  So in this
 | |
| specific case, significant digits are preserved, rather than cancelled.
 | |
| 
 | |
| For other types which do have a __lanczos defined for them 
 | |
| the current solution is as follows: imagine we
 | |
| balance the two terms in the __lanczos by dividing the power term by its value
 | |
| at /z = 1/, and then multiplying the Lanczos coefficients by the same value.
 | |
| Now each term will take the value 1 at /z = 1/ and we can rearrange the power terms
 | |
| in terms of log1p.  Likewise if we subtract 1 from the Lanczos sum part 
 | |
| (algebraically, by subtracting the value of each term at /z = 1/), we obtain
 | |
| a new summation that can be also be fed into log1p.  Crucially, all of the 
 | |
| terms tend to zero, as /z -> 1/:
 | |
| 
 | |
| [equation lgamm5]
 | |
| 
 | |
| The C[sub k][space] terms in the above are the same as in the __lanczos.
 | |
| 
 | |
| A similar rearrangement can be performed at /z = 2/:
 | |
| 
 | |
| [equation lgamm6]
 | |
| 
 | |
| [endsect][/section:lgamma The Log Gamma Function]
 | |
| 
 | |
| [/ 
 | |
|   Copyright 2006 John Maddock and Paul A. Bristow.
 | |
|   Distributed under the Boost Software License, Version 1.0.
 | |
|   (See accompanying file LICENSE_1_0.txt or copy at
 | |
|   http://www.boost.org/LICENSE_1_0.txt).
 | |
| ]
 |