'use strict';

/*
* The original C++ code and copyright notice is from the [Boost library]{@link http://www.boost.org/doc/libs/1_64_0/boost/math/special_functions/gamma.hpp}.
*
* The implementation has been modified for JavaScript.
*/

/*
* Copyright John Maddock 2006-7, 2013-14.
* Copyright Paul A. Bristow 2007, 2013-14.
* Copyright Nikhar Agrawal 2013-14
* Copyright Christopher Kormanyos 2013-14
* Use, modification and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
*/

// MODULES //

var gammaLanczosSum = require( '@stdlib/math/base/special/gamma-lanczos-sum' );
var isNegativeZero = require( '@stdlib/math/base/assert/is-negative-zero' );
var isInteger = require( '@stdlib/math/base/assert/is-integer' );
var isnan = require( '@stdlib/math/base/assert/is-nan' );
var signum = require( '@stdlib/math/base/special/signum' );
var floor = require( '@stdlib/math/base/special/floor' );
var abs = require( '@stdlib/math/base/special/abs' );
var exp = require( '@stdlib/math/base/special/exp' );
var pow = require( '@stdlib/math/base/special/pow' );
var ln = require( '@stdlib/math/base/special/ln' );
var SQRT_EPSILON = require( '@stdlib/math/constants/float64-sqrt-eps' );
var LANCZOS_G = require( '@stdlib/math/constants/float64-gamma-lanczos-g' );
var EULERGAMMA = require( '@stdlib/math/constants/float64-eulergamma' );
var MAX_VALUE = require( '@stdlib/math/constants/float64-max' );
var MAX_LN = require( '@stdlib/math/constants/float64-max-ln' );
var PINF = require( '@stdlib/math/constants/float64-pinf' );
var NINF = require( '@stdlib/math/constants/float64-ninf' );
var PI = require( '@stdlib/math/constants/float64-pi' );
var sinpx = require( './sinpx.js' );
var FACTORIALS = require( './factorials.json' );


// VARIABLES //

var MAX_FACTORIAL = 170;
var HALF = 0.5;


// MAIN //

/**
* Evaluates the gamma function.
*
* @param {number} x - input value
* @returns {number} function value
*
* @example
* var v = gamma( 4.0 );
* // returns 6.0
*
* @example
* var v = gamma( -1.5 );
* // returns ~2.363
*
* @example
* var v = gamma( -0.5 );
* // returns ~-3.545
*
* @example
* var v = gamma( 0.5 );
* // returns ~1.772
*
* @example
* var v = gamma( 0.0 );
* // returns Number.POSITIVE_INFINITY
*
* @example
* var v = gamma( -0.0 );
* // returns Number.NEGATIVE_INFINITY
*
* @example
* var v = gamma( NaN );
* // returns NaN
*/
function gamma( x ) {
	var result;
	var lzgh;
	var zgh;
	var hp;

	if ( x === NINF || isnan( x ) ) {
		return NaN;
	}
	if ( x === 0.0 ) {
		if ( isNegativeZero( x ) ) {
			return NINF;
		}
		return PINF;
	}
	result = 1.0;
	if ( x < 0.0 ) {
		if ( isInteger( x ) ) {
			return NaN;
		}
		if ( x <= -20.0 ) {
			result = gamma( -x ) * sinpx( x );
			if ( abs(result) < 1.0 && MAX_VALUE * abs(result) < PI ) {
				return signum( result ) === 1 ? NINF : PINF;
			}
			result = -PI / result;
			return result;
		}
		// Shift x to > 1:
		while ( x < 0.0 ) {
			result /= x;
			x += 1.0;
		}
	}
	if ( floor( x ) === x && x < MAX_FACTORIAL ) {
		result *= FACTORIALS[ floor( x ) - 1 ];
	}
	else if ( x < SQRT_EPSILON ) {
		if ( x < 1.0 / MAX_VALUE ) {
			result = PINF;
		}
		result *= ( 1.0 / x ) - EULERGAMMA;
	}
	else {
		result *= gammaLanczosSum( x );
		zgh = ( x + LANCZOS_G - HALF );
		lzgh = ln( zgh );
		if ( x * lzgh > MAX_LN ) {
			// We're going to overflow unless this is done with care:
			if ( lzgh * x / 2.0 > MAX_LN ) {
				return signum( result ) === 1 ? PINF : NINF;
			}
			hp = pow( zgh, ( x / 2.0 ) - 0.25 );
			result *= hp / exp( zgh );
			if ( MAX_VALUE / hp < result ) {
				return signum( result ) === 1 ? PINF : NINF;
			}
			result *= hp;
		} else {
			result *= pow( zgh, x - HALF ) / exp( zgh );
		}
	}
	return result;
} // end FUNCTION gamma()


// EXPORTS //

module.exports = gamma;

@@ -351,16 +351,17 @@
  2013-14
+.
 %0A* Copyr
@@ -394,16 +394,17 @@
  2013-14
+.
 %0A* Use, 

Add periods