xref: /netbsd-src/external/gpl3/gcc.old/dist/libphobos/src/std/mathspecial.d (revision 627f7eb200a4419d89b531d55fccd2ee3ffdcde0)
1*627f7eb2Smrg // Written in the D programming language.
2*627f7eb2Smrg 
3*627f7eb2Smrg /**
4*627f7eb2Smrg  * Mathematical Special Functions
5*627f7eb2Smrg  *
6*627f7eb2Smrg  * The technical term 'Special Functions' includes several families of
7*627f7eb2Smrg  * transcendental functions, which have important applications in particular
8*627f7eb2Smrg  * branches of mathematics and physics.
9*627f7eb2Smrg  *
10*627f7eb2Smrg  * The gamma and related functions, and the error function are crucial for
11*627f7eb2Smrg  * mathematical statistics.
12*627f7eb2Smrg  * The Bessel and related functions arise in problems involving wave propagation
13*627f7eb2Smrg  * (especially in optics).
14*627f7eb2Smrg  * Other major categories of special functions include the elliptic integrals
15*627f7eb2Smrg  * (related to the arc length of an ellipse), and the hypergeometric functions.
16*627f7eb2Smrg  *
17*627f7eb2Smrg  * Status:
18*627f7eb2Smrg  *  Many more functions will be added to this module.
19*627f7eb2Smrg  *  The naming convention for the distribution functions (gammaIncomplete, etc)
20*627f7eb2Smrg  *  is not yet finalized and will probably change.
21*627f7eb2Smrg  *
22*627f7eb2Smrg  * Macros:
23*627f7eb2Smrg  *      TABLE_SV = <table border="1" cellpadding="4" cellspacing="0">
24*627f7eb2Smrg  *              <caption>Special Values</caption>
25*627f7eb2Smrg  *              $0</table>
26*627f7eb2Smrg  *      SVH = $(TR $(TH $1) $(TH $2))
27*627f7eb2Smrg  *      SV  = $(TR $(TD $1) $(TD $2))
28*627f7eb2Smrg  *
29*627f7eb2Smrg  *      NAN = $(RED NAN)
30*627f7eb2Smrg  *      SUP = <span style="vertical-align:super;font-size:smaller">$0</span>
31*627f7eb2Smrg  *      GAMMA = &#915;
32*627f7eb2Smrg  *      THETA = &theta;
33*627f7eb2Smrg  *      INTEGRAL = &#8747;
34*627f7eb2Smrg  *      INTEGRATE = $(BIG &#8747;<sub>$(SMALL $1)</sub><sup>$2</sup>)
35*627f7eb2Smrg  *      POWER = $1<sup>$2</sup>
36*627f7eb2Smrg  *      SUB = $1<sub>$2</sub>
37*627f7eb2Smrg  *      BIGSUM = $(BIG &Sigma; <sup>$2</sup><sub>$(SMALL $1)</sub>)
38*627f7eb2Smrg  *      CHOOSE = $(BIG &#40;) <sup>$(SMALL $1)</sup><sub>$(SMALL $2)</sub> $(BIG &#41;)
39*627f7eb2Smrg  *      PLUSMN = &plusmn;
40*627f7eb2Smrg  *      INFIN = &infin;
41*627f7eb2Smrg  *      PLUSMNINF = &plusmn;&infin;
42*627f7eb2Smrg  *      PI = &pi;
43*627f7eb2Smrg  *      LT = &lt;
44*627f7eb2Smrg  *      GT = &gt;
45*627f7eb2Smrg  *      SQRT = &radic;
46*627f7eb2Smrg  *      HALF = &frac12;
47*627f7eb2Smrg  *
48*627f7eb2Smrg  *
49*627f7eb2Smrg  * Copyright: Based on the CEPHES math library, which is
50*627f7eb2Smrg  *            Copyright (C) 1994 Stephen L. Moshier (moshier@world.std.com).
51*627f7eb2Smrg  * License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
52*627f7eb2Smrg  * Authors:   Stephen L. Moshier (original C code). Conversion to D by Don Clugston
53*627f7eb2Smrg  * Source:    $(PHOBOSSRC std/_mathspecial.d)
54*627f7eb2Smrg  */
55*627f7eb2Smrg module std.mathspecial;
56*627f7eb2Smrg import std.internal.math.errorfunction;
57*627f7eb2Smrg import std.internal.math.gammafunction;
58*627f7eb2Smrg public import std.math;
59*627f7eb2Smrg 
60*627f7eb2Smrg /* ***********************************************
61*627f7eb2Smrg  *            GAMMA AND RELATED FUNCTIONS        *
62*627f7eb2Smrg  * ***********************************************/
63*627f7eb2Smrg 
64*627f7eb2Smrg pure:
65*627f7eb2Smrg nothrow:
66*627f7eb2Smrg @safe:
67*627f7eb2Smrg @nogc:
68*627f7eb2Smrg 
69*627f7eb2Smrg /** The Gamma function, $(GAMMA)(x)
70*627f7eb2Smrg  *
71*627f7eb2Smrg  *  $(GAMMA)(x) is a generalisation of the factorial function
72*627f7eb2Smrg  *  to real and complex numbers.
73*627f7eb2Smrg  *  Like x!, $(GAMMA)(x+1) = x * $(GAMMA)(x).
74*627f7eb2Smrg  *
75*627f7eb2Smrg  *  Mathematically, if z.re > 0 then
76*627f7eb2Smrg  *   $(GAMMA)(z) = $(INTEGRATE 0, $(INFIN)) $(POWER t, z-1)$(POWER e, -t) dt
77*627f7eb2Smrg  *
78*627f7eb2Smrg  *  $(TABLE_SV
79*627f7eb2Smrg  *    $(SVH  x,           $(GAMMA)(x) )
80*627f7eb2Smrg  *    $(SV  $(NAN),       $(NAN)      )
81*627f7eb2Smrg  *    $(SV  $(PLUSMN)0.0, $(PLUSMNINF))
82*627f7eb2Smrg  *    $(SV integer > 0,   (x-1)!      )
83*627f7eb2Smrg  *    $(SV integer < 0,   $(NAN)      )
84*627f7eb2Smrg  *    $(SV +$(INFIN),      +$(INFIN)   )
85*627f7eb2Smrg  *    $(SV -$(INFIN),      $(NAN)      )
86*627f7eb2Smrg  *  )
87*627f7eb2Smrg  */
gamma(real x)88*627f7eb2Smrg real gamma(real x)
89*627f7eb2Smrg {
90*627f7eb2Smrg     return std.internal.math.gammafunction.gamma(x);
91*627f7eb2Smrg }
92*627f7eb2Smrg 
93*627f7eb2Smrg /** Natural logarithm of the gamma function, $(GAMMA)(x)
94*627f7eb2Smrg  *
95*627f7eb2Smrg  * Returns the base e (2.718...) logarithm of the absolute
96*627f7eb2Smrg  * value of the gamma function of the argument.
97*627f7eb2Smrg  *
98*627f7eb2Smrg  * For reals, logGamma is equivalent to log(fabs(gamma(x))).
99*627f7eb2Smrg  *
100*627f7eb2Smrg  *  $(TABLE_SV
101*627f7eb2Smrg  *    $(SVH  x,             logGamma(x)   )
102*627f7eb2Smrg  *    $(SV  $(NAN),         $(NAN)      )
103*627f7eb2Smrg  *    $(SV integer <= 0,    +$(INFIN)    )
104*627f7eb2Smrg  *    $(SV $(PLUSMNINF),    +$(INFIN)    )
105*627f7eb2Smrg  *  )
106*627f7eb2Smrg  */
logGamma(real x)107*627f7eb2Smrg real logGamma(real x)
108*627f7eb2Smrg {
109*627f7eb2Smrg     return std.internal.math.gammafunction.logGamma(x);
110*627f7eb2Smrg }
111*627f7eb2Smrg 
112*627f7eb2Smrg /** The sign of $(GAMMA)(x).
113*627f7eb2Smrg  *
114*627f7eb2Smrg  * Returns -1 if $(GAMMA)(x) < 0,  +1 if $(GAMMA)(x) > 0,
115*627f7eb2Smrg  * $(NAN) if sign is indeterminate.
116*627f7eb2Smrg  *
117*627f7eb2Smrg  * Note that this function can be used in conjunction with logGamma(x) to
118*627f7eb2Smrg  * evaluate gamma for very large values of x.
119*627f7eb2Smrg  */
sgnGamma(real x)120*627f7eb2Smrg real sgnGamma(real x)
121*627f7eb2Smrg {
122*627f7eb2Smrg     /* Author: Don Clugston. */
123*627f7eb2Smrg     if (isNaN(x)) return x;
124*627f7eb2Smrg     if (x > 0) return 1.0;
125*627f7eb2Smrg     if (x < -1/real.epsilon)
126*627f7eb2Smrg     {
127*627f7eb2Smrg         // Large negatives lose all precision
128*627f7eb2Smrg         return real.nan;
129*627f7eb2Smrg     }
130*627f7eb2Smrg     long n = rndtol(x);
131*627f7eb2Smrg     if (x == n)
132*627f7eb2Smrg     {
133*627f7eb2Smrg         return x == 0 ?  copysign(1, x) : real.nan;
134*627f7eb2Smrg     }
135*627f7eb2Smrg     return n & 1 ? 1.0 : -1.0;
136*627f7eb2Smrg }
137*627f7eb2Smrg 
138*627f7eb2Smrg @safe unittest
139*627f7eb2Smrg {
140*627f7eb2Smrg     assert(sgnGamma(5.0) == 1.0);
141*627f7eb2Smrg     assert(isNaN(sgnGamma(-3.0)));
142*627f7eb2Smrg     assert(sgnGamma(-0.1) == -1.0);
143*627f7eb2Smrg     assert(sgnGamma(-55.1) == 1.0);
144*627f7eb2Smrg     assert(isNaN(sgnGamma(-real.infinity)));
145*627f7eb2Smrg     assert(isIdentical(sgnGamma(NaN(0xABC)), NaN(0xABC)));
146*627f7eb2Smrg }
147*627f7eb2Smrg 
148*627f7eb2Smrg /** Beta function
149*627f7eb2Smrg  *
150*627f7eb2Smrg  * The beta function is defined as
151*627f7eb2Smrg  *
152*627f7eb2Smrg  * beta(x, y) = ($(GAMMA)(x) * $(GAMMA)(y)) / $(GAMMA)(x + y)
153*627f7eb2Smrg  */
beta(real x,real y)154*627f7eb2Smrg real beta(real x, real y)
155*627f7eb2Smrg {
156*627f7eb2Smrg     if ((x+y)> MAXGAMMA)
157*627f7eb2Smrg     {
158*627f7eb2Smrg         return exp(logGamma(x) + logGamma(y) - logGamma(x+y));
159*627f7eb2Smrg     } else return gamma(x) * gamma(y) / gamma(x+y);
160*627f7eb2Smrg }
161*627f7eb2Smrg 
162*627f7eb2Smrg @safe unittest
163*627f7eb2Smrg {
164*627f7eb2Smrg     assert(isIdentical(beta(NaN(0xABC), 4), NaN(0xABC)));
165*627f7eb2Smrg     assert(isIdentical(beta(2, NaN(0xABC)), NaN(0xABC)));
166*627f7eb2Smrg }
167*627f7eb2Smrg 
168*627f7eb2Smrg /** Digamma function
169*627f7eb2Smrg  *
170*627f7eb2Smrg  *  The digamma function is the logarithmic derivative of the gamma function.
171*627f7eb2Smrg  *
172*627f7eb2Smrg  *  digamma(x) = d/dx logGamma(x)
173*627f7eb2Smrg  *
174*627f7eb2Smrg  *  See_Also: $(LREF logmdigamma), $(LREF logmdigammaInverse).
175*627f7eb2Smrg  */
digamma(real x)176*627f7eb2Smrg real digamma(real x)
177*627f7eb2Smrg {
178*627f7eb2Smrg     return std.internal.math.gammafunction.digamma(x);
179*627f7eb2Smrg }
180*627f7eb2Smrg 
181*627f7eb2Smrg /** Log Minus Digamma function
182*627f7eb2Smrg  *
183*627f7eb2Smrg  *  logmdigamma(x) = log(x) - digamma(x)
184*627f7eb2Smrg  *
185*627f7eb2Smrg  *  See_Also: $(LREF digamma), $(LREF logmdigammaInverse).
186*627f7eb2Smrg  */
logmdigamma(real x)187*627f7eb2Smrg real logmdigamma(real x)
188*627f7eb2Smrg {
189*627f7eb2Smrg     return std.internal.math.gammafunction.logmdigamma(x);
190*627f7eb2Smrg }
191*627f7eb2Smrg 
192*627f7eb2Smrg /** Inverse of the Log Minus Digamma function
193*627f7eb2Smrg  *
194*627f7eb2Smrg  *  Given y, the function finds x such log(x) - digamma(x) = y.
195*627f7eb2Smrg  *
196*627f7eb2Smrg  *  See_Also: $(LREF logmdigamma), $(LREF digamma).
197*627f7eb2Smrg  */
logmdigammaInverse(real x)198*627f7eb2Smrg real logmdigammaInverse(real x)
199*627f7eb2Smrg {
200*627f7eb2Smrg     return std.internal.math.gammafunction.logmdigammaInverse(x);
201*627f7eb2Smrg }
202*627f7eb2Smrg 
203*627f7eb2Smrg /** Incomplete beta integral
204*627f7eb2Smrg  *
205*627f7eb2Smrg  * Returns incomplete beta integral of the arguments, evaluated
206*627f7eb2Smrg  * from zero to x. The regularized incomplete beta function is defined as
207*627f7eb2Smrg  *
208*627f7eb2Smrg  * betaIncomplete(a, b, x) = $(GAMMA)(a + b) / ( $(GAMMA)(a) $(GAMMA)(b) ) *
209*627f7eb2Smrg  * $(INTEGRATE 0, x) $(POWER t, a-1)$(POWER (1-t), b-1) dt
210*627f7eb2Smrg  *
211*627f7eb2Smrg  * and is the same as the the cumulative distribution function.
212*627f7eb2Smrg  *
213*627f7eb2Smrg  * The domain of definition is 0 <= x <= 1.  In this
214*627f7eb2Smrg  * implementation a and b are restricted to positive values.
215*627f7eb2Smrg  * The integral from x to 1 may be obtained by the symmetry
216*627f7eb2Smrg  * relation
217*627f7eb2Smrg  *
218*627f7eb2Smrg  *    betaIncompleteCompl(a, b, x )  =  betaIncomplete( b, a, 1-x )
219*627f7eb2Smrg  *
220*627f7eb2Smrg  * The integral is evaluated by a continued fraction expansion
221*627f7eb2Smrg  * or, when b * x is small, by a power series.
222*627f7eb2Smrg  */
betaIncomplete(real a,real b,real x)223*627f7eb2Smrg real betaIncomplete(real a, real b, real x )
224*627f7eb2Smrg {
225*627f7eb2Smrg     return std.internal.math.gammafunction.betaIncomplete(a, b, x);
226*627f7eb2Smrg }
227*627f7eb2Smrg 
228*627f7eb2Smrg /** Inverse of incomplete beta integral
229*627f7eb2Smrg  *
230*627f7eb2Smrg  * Given y, the function finds x such that
231*627f7eb2Smrg  *
232*627f7eb2Smrg  *  betaIncomplete(a, b, x) == y
233*627f7eb2Smrg  *
234*627f7eb2Smrg  *  Newton iterations or interval halving is used.
235*627f7eb2Smrg  */
betaIncompleteInverse(real a,real b,real y)236*627f7eb2Smrg real betaIncompleteInverse(real a, real b, real y )
237*627f7eb2Smrg {
238*627f7eb2Smrg     return std.internal.math.gammafunction.betaIncompleteInv(a, b, y);
239*627f7eb2Smrg }
240*627f7eb2Smrg 
241*627f7eb2Smrg /** Incomplete gamma integral and its complement
242*627f7eb2Smrg  *
243*627f7eb2Smrg  * These functions are defined by
244*627f7eb2Smrg  *
245*627f7eb2Smrg  *   gammaIncomplete = ( $(INTEGRATE 0, x) $(POWER e, -t) $(POWER t, a-1) dt )/ $(GAMMA)(a)
246*627f7eb2Smrg  *
247*627f7eb2Smrg  *  gammaIncompleteCompl(a,x)   =   1 - gammaIncomplete(a,x)
248*627f7eb2Smrg  * = ($(INTEGRATE x, $(INFIN)) $(POWER e, -t) $(POWER t, a-1) dt )/ $(GAMMA)(a)
249*627f7eb2Smrg  *
250*627f7eb2Smrg  * In this implementation both arguments must be positive.
251*627f7eb2Smrg  * The integral is evaluated by either a power series or
252*627f7eb2Smrg  * continued fraction expansion, depending on the relative
253*627f7eb2Smrg  * values of a and x.
254*627f7eb2Smrg  */
gammaIncomplete(real a,real x)255*627f7eb2Smrg real gammaIncomplete(real a, real x )
256*627f7eb2Smrg in {
257*627f7eb2Smrg    assert(x >= 0);
258*627f7eb2Smrg    assert(a > 0);
259*627f7eb2Smrg }
260*627f7eb2Smrg body {
261*627f7eb2Smrg     return std.internal.math.gammafunction.gammaIncomplete(a, x);
262*627f7eb2Smrg }
263*627f7eb2Smrg 
264*627f7eb2Smrg /** ditto */
gammaIncompleteCompl(real a,real x)265*627f7eb2Smrg real gammaIncompleteCompl(real a, real x )
266*627f7eb2Smrg in {
267*627f7eb2Smrg    assert(x >= 0);
268*627f7eb2Smrg    assert(a > 0);
269*627f7eb2Smrg }
270*627f7eb2Smrg body {
271*627f7eb2Smrg     return std.internal.math.gammafunction.gammaIncompleteCompl(a, x);
272*627f7eb2Smrg }
273*627f7eb2Smrg 
274*627f7eb2Smrg /** Inverse of complemented incomplete gamma integral
275*627f7eb2Smrg  *
276*627f7eb2Smrg  * Given a and p, the function finds x such that
277*627f7eb2Smrg  *
278*627f7eb2Smrg  *  gammaIncompleteCompl( a, x ) = p.
279*627f7eb2Smrg  */
gammaIncompleteComplInverse(real a,real p)280*627f7eb2Smrg real gammaIncompleteComplInverse(real a, real p)
281*627f7eb2Smrg in {
282*627f7eb2Smrg   assert(p >= 0 && p <= 1);
283*627f7eb2Smrg   assert(a > 0);
284*627f7eb2Smrg }
285*627f7eb2Smrg body {
286*627f7eb2Smrg     return std.internal.math.gammafunction.gammaIncompleteComplInv(a, p);
287*627f7eb2Smrg }
288*627f7eb2Smrg 
289*627f7eb2Smrg 
290*627f7eb2Smrg /* ***********************************************
291*627f7eb2Smrg  *     ERROR FUNCTIONS & NORMAL DISTRIBUTION     *
292*627f7eb2Smrg  * ***********************************************/
293*627f7eb2Smrg 
294*627f7eb2Smrg  /** Error function
295*627f7eb2Smrg  *
296*627f7eb2Smrg  * The integral is
297*627f7eb2Smrg  *
298*627f7eb2Smrg  *  erf(x) =  2/ $(SQRT)($(PI))
299*627f7eb2Smrg  *     $(INTEGRATE 0, x) exp( - $(POWER t, 2)) dt
300*627f7eb2Smrg  *
301*627f7eb2Smrg  * The magnitude of x is limited to about 106.56 for IEEE 80-bit
302*627f7eb2Smrg  * arithmetic; 1 or -1 is returned outside this range.
303*627f7eb2Smrg  */
erf(real x)304*627f7eb2Smrg real erf(real x)
305*627f7eb2Smrg {
306*627f7eb2Smrg     return std.internal.math.errorfunction.erf(x);
307*627f7eb2Smrg }
308*627f7eb2Smrg 
309*627f7eb2Smrg /** Complementary error function
310*627f7eb2Smrg  *
311*627f7eb2Smrg  * erfc(x) = 1 - erf(x)
312*627f7eb2Smrg  *         = 2/ $(SQRT)($(PI))
313*627f7eb2Smrg  *     $(INTEGRATE x, $(INFIN)) exp( - $(POWER t, 2)) dt
314*627f7eb2Smrg  *
315*627f7eb2Smrg  * This function has high relative accuracy for
316*627f7eb2Smrg  * values of x far from zero. (For values near zero, use erf(x)).
317*627f7eb2Smrg  */
erfc(real x)318*627f7eb2Smrg real erfc(real x)
319*627f7eb2Smrg {
320*627f7eb2Smrg     return std.internal.math.errorfunction.erfc(x);
321*627f7eb2Smrg }
322*627f7eb2Smrg 
323*627f7eb2Smrg 
324*627f7eb2Smrg /** Normal distribution function.
325*627f7eb2Smrg  *
326*627f7eb2Smrg  * The normal (or Gaussian, or bell-shaped) distribution is
327*627f7eb2Smrg  * defined as:
328*627f7eb2Smrg  *
329*627f7eb2Smrg  * normalDist(x) = 1/$(SQRT)(2$(PI)) $(INTEGRATE -$(INFIN), x) exp( - $(POWER t, 2)/2) dt
330*627f7eb2Smrg  *   = 0.5 + 0.5 * erf(x/sqrt(2))
331*627f7eb2Smrg  *   = 0.5 * erfc(- x/sqrt(2))
332*627f7eb2Smrg  *
333*627f7eb2Smrg  * To maintain accuracy at values of x near 1.0, use
334*627f7eb2Smrg  *      normalDistribution(x) = 1.0 - normalDistribution(-x).
335*627f7eb2Smrg  *
336*627f7eb2Smrg  * References:
337*627f7eb2Smrg  * $(LINK http://www.netlib.org/cephes/ldoubdoc.html),
338*627f7eb2Smrg  * G. Marsaglia, "Evaluating the Normal Distribution",
339*627f7eb2Smrg  * Journal of Statistical Software <b>11</b>, (July 2004).
340*627f7eb2Smrg  */
normalDistribution(real x)341*627f7eb2Smrg real normalDistribution(real x)
342*627f7eb2Smrg {
343*627f7eb2Smrg     return std.internal.math.errorfunction.normalDistributionImpl(x);
344*627f7eb2Smrg }
345*627f7eb2Smrg 
346*627f7eb2Smrg /** Inverse of Normal distribution function
347*627f7eb2Smrg  *
348*627f7eb2Smrg  * Returns the argument, x, for which the area under the
349*627f7eb2Smrg  * Normal probability density function (integrated from
350*627f7eb2Smrg  * minus infinity to x) is equal to p.
351*627f7eb2Smrg  *
352*627f7eb2Smrg  * Note: This function is only implemented to 80 bit precision.
353*627f7eb2Smrg  */
normalDistributionInverse(real p)354*627f7eb2Smrg real normalDistributionInverse(real p)
355*627f7eb2Smrg in {
356*627f7eb2Smrg   assert(p >= 0.0L && p <= 1.0L, "Domain error");
357*627f7eb2Smrg }
358*627f7eb2Smrg body
359*627f7eb2Smrg {
360*627f7eb2Smrg     return std.internal.math.errorfunction.normalDistributionInvImpl(p);
361*627f7eb2Smrg }
362