UNPKG

@stdlib/math-base-special-gammaincinv

Version:

Inverse incomplete gamma function.

123 lines (109 loc) 3.08 kB
/** * @license Apache-2.0 * * Copyright (c) 2018 The Stdlib Authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 'use strict'; // MODULES // var logger = require( 'debug' ); var gammainc = require( '@stdlib/math-base-special-gammainc' ); var abs = require( '@stdlib/math-base-special-abs' ); var exp = require( '@stdlib/math-base-special-exp' ); var ln = require( '@stdlib/math-base-special-ln' ); var MAX_FLOAT32 = require( '@stdlib/constants-float32-max' ); // VARIABLES // var debug = logger( 'gammaincinv:higher_newton' ); // MAIN // /** * Implementation of the high order Newton-like method. * * @private * @param {number} x0 - initial value * @param {number} a - scale parameter * @param {number} m - indicator * @param {Probability} p - probability value * @param {Probability} q - probability value * @param {number} lgama - logarithm of scale parameter * @param {number} invfp - one over `fp` * @param {boolean} pcase - boolean indicating whether p < 0.5 * @returns {number} function value of the inverse */ function higherNewton( x0, a, m, p, q, lgama, invfp, pcase ) { var dlnr; var xini; var ck0; var ck1; var ck2; var a2; var x2; var px; var qx; var xr; var t; var n; var r; var x; x = x0; t = 1; n = 1; a2 = a * a; xini = x0; do { x = x0; x2 = x * x; if ( m === 0 ) { dlnr = ( ( 1.0-a ) * ln( x ) ) + x + lgama; if ( dlnr > ln( MAX_FLOAT32 ) ) { debug( 'Warning: overflow problems in one or more steps of the computation. The initial approximation to the root is returned.' ); return xini; } r = exp( dlnr ); } else { r = -invfp * x; } if ( pcase ) { // Call: gammainc( x, s[, regularized = true ][, upper = false ] ) px = gammainc( x, a, true, false ); ck0 = -r * ( px - p ); } else { // Call: gammainc( x, s[, regularized = true ][, upper = true ] ) qx = gammainc( x, a, true, true ); ck0 = r * ( qx - q ); } r = ck0; if ( ( p > 1e-120 ) || ( n > 1 ) ) { ck1 = 0.5 * ( x - a + 1.0 ) / x; ck2 = ( (2*x2) - (4*x*a) + (4*x) + (2*a2) - (3*a) + 1 ) / x2; ck2 /= 6.0; x0 = x + ( r * ( 1.0 + ( r * ( ck1 + (r*ck2) ) ) ) ); } else { x0 = x + r; } t = abs( ( x/x0 ) - 1.0 ); n += 1; x = x0; if ( x < 0 ) { x = xini; n = 100; } } while ( ( ( t > 2e-14 ) && ( n < 35 ) ) ); if ( ( t > 2e-14 ) || ( n > 99 ) ) { debug( 'Warning: the number of iterations in the Newton method reached the upper limit N=35. The last value obtained for the root is given as output.' ); } xr = x || 0; return xr; } // EXPORTS // module.exports = higherNewton;