%mathpiper,def="***"

/// partial factorial
n1_IsRationalOrNumber *** n2_IsRationalOrNumber <--
[
	Check(n2-n1 <= 65535, "Argument", "Partial factorial: Error: the range " : ( PipeToString() Write(n2-n1) ) : " is too large, you may want to avoid exact calculation");
	If(n2-n1<0,
		1,
		Factorial'partial(n1, n2)
	);
];

/// recursive routine to evaluate "partial factorial" a*(a+1)*...*b
// TODO lets document why the >>1 as used here is allowed (rounding down? What is the idea behind this algorithm?)
2# Factorial'partial(_a, _b) _ (b-a>=4) <-- Factorial'partial(a, a+((b-a)>>1)) * Factorial'partial(a+((b-a)>>1)+1, b);
3# Factorial'partial(_a, _b) _ (b-a>=3) <-- a*(a+1)*(a+2)*(a+3);
4# Factorial'partial(_a, _b) _ (b-a>=2) <-- a*(a+1)*(a+2);
5# Factorial'partial(_a, _b) _ (b-a>=1) <-- a*(a+1);
6# Factorial'partial(_a, _b) _ (b-a>=0) <-- a;
%/mathpiper




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

*CALL
	a *** b

*PARMS
{a}, {b} -- numbers

*DESC
The "partial factorial" function {a *** b} calculates the product $a*(a+1)*...$ 
which is terminated at the least integer not greater than $b$. The arguments $a$ 
and $b$ do not have to be integers; for integer arguments, {a *** b} = $b! / (a-1)!$. 
This function is sometimes a lot faster than evaluating the two factorials, 
especially if $a$ and $b$ are close together. If $a>b$ the function returns $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> 1/3 *** 10;
Result: 17041024000/59049;

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