%mathpiper,def="!"

/* Factorials */

10 # 0! <-- 1;
10 # (Infinity)! <-- Infinity;
20 # ((n_IsPositiveInteger)!) <-- [
	Check(n <= 65535, "Argument", "Factorial: Error: the argument " : ( PipeToString() Write(n) ) : " is too large, you may want to avoid exact calculation");
	MathFac(n);
];

25 # ((x_IsConstant)!)_(FloatIsInt(x) And x>0) <-- (Round(x)!);

30 # ((x_IsNumber)!)_InNumericMode() <-- Internal'GammaNum(x+1);

40 # (n_IsList)! <-- MapSingle("!",n);

/* formulae for half-integer factorials:

(+(2*z+1)/2)! = Sqrt(Pi)*(2*z+1)! / (2^(2*z+1)*z!) for z >= 0
(-(2*z+1)/2)! = Sqrt(Pi)*(-1)^z*z!*2^(2*z) / (2*z)! for z >= 0

Double factorials are more efficient:
	(2*n-1)!! := 1*3*...*(2*n-1) = (2*n)! / (2^n*n!)
	(2*n)!! := 2*4*...*(2*n) = 2^n*n!

*/
/* // old version - not using double factorials
HalfIntegerFactorial(n_IsOdd) _ (n>0) <--
	Sqrt(Pi) * ( n! / ( 2^n*((n-1)/2)! ) );
HalfIntegerFactorial(n_IsOdd) _ (n<0)  <--
	Sqrt(Pi) * ( (-1)^((-n-1)/2)*2^(-n-1)*((-n-1)/2)! / (-n-1)! );
*/
// new version using double factorials
HalfIntegerFactorial(n_IsOdd) _ (n>0) <--
	Sqrt(Pi) * ( n!! / 2^((n+1)/2) );
HalfIntegerFactorial(n_IsOdd) _ (n<0)  <--
	Sqrt(Pi) * ( (-1)^((-n-1)/2)*2^((-n-1)/2) / (-n-2)!! );
//HalfIntegerFactorial(n_IsOdd) _ (n= -1)  <-- Sqrt(Pi);

/* Want to also compute (2.5)! */
40 # (n_IsRationalOrNumber)! _(Denominator(Rationalize(n))=2) <-- HalfIntegerFactorial(Numerator(Rationalize(n)));


%/mathpiper



%mathpiper_docs,name="!",categories="Operators"
*CMD !  --- factorial

*CALL
	n!
	n!!
	
*PARMS
{n} -- integer, half-integer, or list

*DESC
The factorial function {n!} calculates the factorial of integer or half-integer numbers. For
nonnegative integers, $n! := n*(n-1)*(n-2)*...*1$. The factorial of
half-integers is defined via Euler's Gamma function, $z! := Gamma(z+1)$. If $n=0$ the function returns $1$.

The factorial functions are threaded, meaning that if the argument {n} is a
list, the function will be applied to each element of the list.

Note: For reasons of MathPiper syntax, the factorial sign {!} cannot precede other
non-letter symbols such as {+} or {*}. Therefore, you should enter a space
after {!} in expressions such as {x! +1}.

The factorial functions terminate and print an error message if the arguments are too large (currently the limit 
is $n < 65535$) because exact factorials of such large numbers are computationally expensive and most probably 
not useful. One can call {Internal'LnGammaNum()} to evaluate logarithms of such factorials to desired precision.

*E.G.

In> 5!
Result: 120;
In> 1 * 2 * 3 * 4 * 5
Result: 120;
In> (1/2)!
Result: Sqrt(Pi)/2;

*SEE BinomialCoefficient, Product, Gamma, !!, ***, Subfactorial
%/mathpiper_docs