mirror of
				https://github.com/saitohirga/WSJT-X.git
				synced 2025-11-04 05:50:31 -05:00 
			
		
		
		
	
		
			
	
	
		
			291 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			291 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| 
								 | 
							
								[section:igamma Incomplete Gamma Functions]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[h4 Synopsis]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								``
							 | 
						||
| 
								 | 
							
								#include <boost/math/special_functions/gamma.hpp>
							 | 
						||
| 
								 | 
							
								``
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   namespace boost{ namespace math{
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   template <class T1, class T2>
							 | 
						||
| 
								 | 
							
								   ``__sf_result`` gamma_p(T1 a, T2 z);
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   template <class T1, class T2, class ``__Policy``>
							 | 
						||
| 
								 | 
							
								   ``__sf_result`` gamma_p(T1 a, T2 z, const ``__Policy``&);
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   template <class T1, class T2>
							 | 
						||
| 
								 | 
							
								   ``__sf_result`` gamma_q(T1 a, T2 z);
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   template <class T1, class T2, class ``__Policy``>
							 | 
						||
| 
								 | 
							
								   ``__sf_result`` gamma_q(T1 a, T2 z, const ``__Policy``&);
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   template <class T1, class T2>
							 | 
						||
| 
								 | 
							
								   ``__sf_result`` tgamma_lower(T1 a, T2 z);
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   template <class T1, class T2, class ``__Policy``>
							 | 
						||
| 
								 | 
							
								   ``__sf_result`` tgamma_lower(T1 a, T2 z, const ``__Policy``&);
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   template <class T1, class T2>
							 | 
						||
| 
								 | 
							
								   ``__sf_result`` tgamma(T1 a, T2 z);
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   template <class T1, class T2, class ``__Policy``>
							 | 
						||
| 
								 | 
							
								   ``__sf_result`` tgamma(T1 a, T2 z, const ``__Policy``&);
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   }} // namespaces
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								[h4 Description]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								There are four [@http://mathworld.wolfram.com/IncompleteGammaFunction.html 
							 | 
						||
| 
								 | 
							
								incomplete gamma functions]:
							 | 
						||
| 
								 | 
							
								two are normalised versions (also known as /regularized/ incomplete gamma functions)
							 | 
						||
| 
								 | 
							
								that return values in the range [0, 1], and two are non-normalised and
							 | 
						||
| 
								 | 
							
								return values in the range [0, [Gamma](a)].  Users interested in statistical
							 | 
						||
| 
								 | 
							
								applications should use the
							 | 
						||
| 
								 | 
							
								[@http://mathworld.wolfram.com/RegularizedGammaFunction.html normalised versions (gamma_p and gamma_q)].
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								All of these functions require /a > 0/ and /z >= 0/, otherwise they return
							 | 
						||
| 
								 | 
							
								the result of __domain_error.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[optional_policy]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The return type of these functions is computed using the __arg_promotion_rules
							 | 
						||
| 
								 | 
							
								when T1 and T2 are different types, otherwise the return type is simply T1.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   template <class T1, class T2>
							 | 
						||
| 
								 | 
							
								   ``__sf_result`` gamma_p(T1 a, T2 z);
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   template <class T1, class T2, class Policy>
							 | 
						||
| 
								 | 
							
								   ``__sf_result`` gamma_p(T1 a, T2 z, const ``__Policy``&);
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								Returns the normalised lower incomplete gamma function of a and z:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[equation igamma4]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								This function changes rapidly from 0 to 1 around the point z == a:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[graph gamma_p]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   template <class T1, class T2>
							 | 
						||
| 
								 | 
							
								   ``__sf_result`` gamma_q(T1 a, T2 z);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   template <class T1, class T2, class ``__Policy``>
							 | 
						||
| 
								 | 
							
								   ``__sf_result`` gamma_q(T1 a, T2 z, const ``__Policy``&);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Returns the normalised upper incomplete gamma function of a and z:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[equation igamma3]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								This function changes rapidly from 1 to 0 around the point z == a:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[graph gamma_q]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   template <class T1, class T2>
							 | 
						||
| 
								 | 
							
								   ``__sf_result`` tgamma_lower(T1 a, T2 z);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   template <class T1, class T2, class ``__Policy``>
							 | 
						||
| 
								 | 
							
								   ``__sf_result`` tgamma_lower(T1 a, T2 z, const ``__Policy``&);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Returns the full (non-normalised) lower incomplete gamma function of a and z:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[equation igamma2]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   template <class T1, class T2>
							 | 
						||
| 
								 | 
							
								   ``__sf_result`` tgamma(T1 a, T2 z);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   template <class T1, class T2, class ``__Policy``>
							 | 
						||
| 
								 | 
							
								   ``__sf_result`` tgamma(T1 a, T2 z, const ``__Policy``&);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Returns the full (non-normalised) upper incomplete gamma function of a and z:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[equation igamma1]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[h4 Accuracy]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The following tables give peak and mean relative errors in over various domains of
							 | 
						||
| 
								 | 
							
								a and z, along with comparisons to the __gsl and __cephes libraries.
							 | 
						||
| 
								 | 
							
								Note that only results for the widest floating point type on the system are given as
							 | 
						||
| 
								 | 
							
								narrower types have __zero_error.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Note that errors grow as /a/ grows larger.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Note also that the higher error rates for the 80 and 128 bit 
							 | 
						||
| 
								 | 
							
								long double results are somewhat misleading: expected results that are 
							 | 
						||
| 
								 | 
							
								zero at 64-bit double precision may be non-zero - but exceptionally small -
							 | 
						||
| 
								 | 
							
								with the larger exponent range of a long double.  These results therefore
							 | 
						||
| 
								 | 
							
								reflect the more extreme nature of the tests conducted for these types.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								All values are in units of epsilon.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[table_gamma_p]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[table_gamma_q]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[table_tgamma_lower]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[table_tgamma_incomplete_]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[h4 Testing]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								There are two sets of tests: spot tests compare values taken from
							 | 
						||
| 
								 | 
							
								[@http://functions.wolfram.com/GammaBetaErf/ Mathworld's online evaluator]
							 | 
						||
| 
								 | 
							
								with this implementation to perform a basic "sanity check".
							 | 
						||
| 
								 | 
							
								Accuracy tests use data generated at very high precision
							 | 
						||
| 
								 | 
							
								(using NTL's RR class set at 1000-bit precision) using this implementation 
							 | 
						||
| 
								 | 
							
								with a very high precision 60-term __lanczos, and some but not all of the special
							 | 
						||
| 
								 | 
							
								case handling disabled.
							 | 
						||
| 
								 | 
							
								This is less than satisfactory: an independent method should really be used,
							 | 
						||
| 
								 | 
							
								but apparently a complete lack of such methods are available.  We can't even use a deliberately
							 | 
						||
| 
								 | 
							
								naive implementation without special case handling since Legendre's continued fraction
							 | 
						||
| 
								 | 
							
								(see below) is unstable for small a and z.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[h4 Implementation]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								These four functions share a common implementation since
							 | 
						||
| 
								 | 
							
								they are all related via:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								1) [equation igamma5]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								2) [equation igamma6]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								3) [equation igamma7]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The lower incomplete gamma is computed from its series representation:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								4) [equation igamma8]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Or by subtraction of the upper integral from either [Gamma](a) or 1
							 | 
						||
| 
								 | 
							
								when /x - (1/(3x)) > a and x > 1.1/.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The upper integral is computed from Legendre's continued fraction representation:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								5) [equation igamma9]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								When /(x > 1.1)/ or by subtraction of the lower integral from either [Gamma](a) or 1
							 | 
						||
| 
								 | 
							
								when /x - (1/(3x))  < a/.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								For /x < 1.1/ computation of the upper integral is more complex as the continued 
							 | 
						||
| 
								 | 
							
								fraction representation is unstable in this area.  However there is another 
							 | 
						||
| 
								 | 
							
								series representation for the lower integral:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								6) [equation igamma10]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								That lends itself to calculation of the upper integral via rearrangement
							 | 
						||
| 
								 | 
							
								to:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								7) [equation igamma11]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Refer to the documentation for __powm1 and __tgamma1pm1 for details
							 | 
						||
| 
								 | 
							
								of their implementation.  Note however that the precision of __tgamma1pm1
							 | 
						||
| 
								 | 
							
								is capped to either around 35 digits, or to that of the __lanczos associated with
							 | 
						||
| 
								 | 
							
								type T - if there is one - whichever of the two is the greater.  
							 | 
						||
| 
								 | 
							
								That therefore imposes a similar limit on the precision of this 
							 | 
						||
| 
								 | 
							
								function in this region.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								For /x < 1.1/ the crossover point where the result is ~0.5 no longer
							 | 
						||
| 
								 | 
							
								occurs for /x ~ y/.  Using /x * 0.75 < a/ as the crossover criterion
							 | 
						||
| 
								 | 
							
								for /0.5 < x <= 1.1/ keeps the maximum value computed (whether
							 | 
						||
| 
								 | 
							
								it's the upper or lower interval) to around 0.75.   Likewise for
							 | 
						||
| 
								 | 
							
								/x <= 0.5/ then using /-0.4 / log(x) < a/ as the crossover criterion
							 | 
						||
| 
								 | 
							
								keeps the maximum value computed to around 0.7
							 | 
						||
| 
								 | 
							
								(whether it's the upper or lower interval).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								There are two special cases used when a is an integer or half integer,
							 | 
						||
| 
								 | 
							
								and the crossover conditions listed above indicate that we should compute
							 | 
						||
| 
								 | 
							
								the upper integral Q.
							 | 
						||
| 
								 | 
							
								If a is an integer in the range /1 <= a < 30/ then the following 
							 | 
						||
| 
								 | 
							
								finite sum is used:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								9) [equation igamma1f]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								While for half integers in the range /0.5 <= a < 30/ then the
							 | 
						||
| 
								 | 
							
								following finite sum is used:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								10) [equation igamma2f]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								These are both more stable and more efficient than the continued fraction
							 | 
						||
| 
								 | 
							
								alternative.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								When the argument /a/ is large, and /x ~ a/ then the series (4) and continued 
							 | 
						||
| 
								 | 
							
								fraction (5) above are very slow to converge.  In this area an expansion due to
							 | 
						||
| 
								 | 
							
								Temme is used:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								11) [equation igamma16]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								12) [equation igamma17]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								13) [equation igamma18]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								14) [equation igamma19]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The double sum is truncated to a fixed number of terms - to give a specific
							 | 
						||
| 
								 | 
							
								target precision - and evaluated as a polynomial-of-polynomials.  There are 
							 | 
						||
| 
								 | 
							
								versions for up to 128-bit long double precision: types requiring
							 | 
						||
| 
								 | 
							
								greater precision than that do not use these expansions.  The
							 | 
						||
| 
								 | 
							
								coefficients C[sub k][super n] are computed in advance using the recurrence
							 | 
						||
| 
								 | 
							
								relations given by Temme.  The zone where these expansions are used is
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   (a > 20) && (a < 200) && fabs(x-a)/a < 0.4
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								And:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   (a > 200) && (fabs(x-a)/a < 4.5/sqrt(a))
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								The latter range is valid for all types up to 128-bit long doubles, and
							 | 
						||
| 
								 | 
							
								is designed to ensure that the result is larger than 10[super -6], the 
							 | 
						||
| 
								 | 
							
								first range is used only for types up to 80-bit long doubles.  These
							 | 
						||
| 
								 | 
							
								domains are narrower than the ones recommended by either Temme or Didonato
							 | 
						||
| 
								 | 
							
								and Morris.  However, using a wider range results in large and inexact
							 | 
						||
| 
								 | 
							
								(i.e. computed) values being passed to the `exp` and `erfc` functions
							 | 
						||
| 
								 | 
							
								resulting in significantly larger error rates.  In other words there is a
							 | 
						||
| 
								 | 
							
								fine trade off here between efficiency and error.  The current limits should
							 | 
						||
| 
								 | 
							
								keep the number of terms required by (4) and (5) to no more than ~20
							 | 
						||
| 
								 | 
							
								at double precision.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								For the normalised incomplete gamma functions, calculation of the 
							 | 
						||
| 
								 | 
							
								leading power terms is central to the accuracy of the function.
							 | 
						||
| 
								 | 
							
								For smallish a and x combining
							 | 
						||
| 
								 | 
							
								the power terms with the __lanczos gives the greatest accuracy:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								15) [equation igamma12]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								In the event that this causes underflow/overflow then the exponent can 
							 | 
						||
| 
								 | 
							
								be reduced by a factor of /a/ and brought inside the power term.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								When a and x are large, we end up with a very large exponent with a base
							 | 
						||
| 
								 | 
							
								near one: this will not be computed accurately via the pow function,
							 | 
						||
| 
								 | 
							
								and taking logs simply leads to cancellation errors.  The worst of the
							 | 
						||
| 
								 | 
							
								errors can be avoided by using:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								16) [equation igamma13]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								when /a-x/ is small and a and x are large.  There is still a subtraction
							 | 
						||
| 
								 | 
							
								and therefore some cancellation errors - but the terms are small so the absolute
							 | 
						||
| 
								 | 
							
								error will be small - and it is absolute rather than relative error that 
							 | 
						||
| 
								 | 
							
								counts in the argument to the /exp/ function.  Note that for sufficiently
							 | 
						||
| 
								 | 
							
								large a and x the errors will still get you eventually, although this does
							 | 
						||
| 
								 | 
							
								delay the inevitable much longer than other methods.  Use of /log(1+x)-x/ here
							 | 
						||
| 
								 | 
							
								is inspired by Temme (see references below).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[h4 References]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								* N. M. Temme, A Set of Algorithms for the Incomplete Gamma Functions,
							 | 
						||
| 
								 | 
							
								Probability in the Engineering and Informational Sciences, 8, 1994.
							 | 
						||
| 
								 | 
							
								* N. M. Temme, The Asymptotic Expansion of the Incomplete Gamma Functions,
							 | 
						||
| 
								 | 
							
								Siam J. Math Anal. Vol 10 No 4, July 1979, p757.
							 | 
						||
| 
								 | 
							
								* A. R. Didonato and A. H. Morris, Computation of the Incomplete Gamma 
							 | 
						||
| 
								 | 
							
								Function Ratios and their Inverse.  ACM TOMS, Vol 12, No 4, Dec 1986, p377.
							 | 
						||
| 
								 | 
							
								* W. Gautschi, The Incomplete Gamma Functions Since Tricomi, In Tricomi's Ideas 
							 | 
						||
| 
								 | 
							
								and Contemporary Applied Mathematics, Atti dei Convegni Lincei, n. 147, 
							 | 
						||
| 
								 | 
							
								Accademia Nazionale dei Lincei, Roma, 1998, pp. 203--237. 
							 | 
						||
| 
								 | 
							
								[@http://citeseer.ist.psu.edu/gautschi98incomplete.html http://citeseer.ist.psu.edu/gautschi98incomplete.html]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[endsect][/section:igamma The Incomplete 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).
							 | 
						||
| 
								 | 
							
								]
							 |