%mathpiper,def="IntNthRoot"

/// Compute integer part of s-th root of (positive) integer n.
// algorithm using floating-point math
10 # IntNthRoot(_n, 2) <-- Floor(SqrtN(n));
20 # IntNthRoot(_n, s_IsInteger) <--
[
	Local(result, k);
	GlobalPush(BuiltinPrecisionGet());
	// find integer k such that 2^k <= n^(1/s) < 2^(k+1)
	k := Quotient(IntLog(n, 2), s);
	// therefore we need k*Ln(2)/Ln(10) digits for the floating-point calculation
	BuiltinPrecisionSet(2+Quotient(k*3361, 11165));	// 643/2136 < Ln(2)/Ln(10) < 3361/11165
	result := Round(ExpN(DivideN(Internal'LnNum(DivideN(n, 2^(k*s))), s))*2^k);
	BuiltinPrecisionSet(GlobalPop());
	// result is rounded and so it may overshoot (we do not use Floor above because numerical calculations may undershoot)
	If(result^s>n, result-1, result);
];

/* algorithm using only integer arithmetic.
(this is slower than the floating-point algorithm for large numbers because all calculations are with long integers)
IntNthRoot1(_n, s_IsInteger) <--
[
	Local(x1, x2, x'new, y1);
	// initial guess should always undershoot
	//	x1:= 2 ^ Quotient(IntLog(n, 2), s); 	// this is worse than we can make it
	x1 := IntLog(n,2);
	// select initial interval using (the number of bits in n) mod s
	// note that if the answer is 1, the initial guess must also be 1 (not 0)
	x2 := Quotient(x1, s);	// save these values for the next If()
	x1 := Modulo(x1, s)/s;	// this is kept as a fraction
	// now assign the initial interval, x1 <= root <= x2
	{x1, x2} := If(
		x1 >= 263/290,	// > Ln(15/8)/Ln(2)
		Quotient({15,16}*2^x2, 8),
		If(
		x1 >= 373/462,	// > Ln(7/4)/Ln(2)
		Quotient({7,8}*2^x2, 4),
		If(
		x1 >= 179/306,	// > Ln(3/2)/Ln(2)
		Quotient({6,7}*2^x2, 4),
		If(
		x1 >= 113/351,	// > Ln(5/4)/Ln(2)
		Quotient({5,6}*2^x2, 4),
		Quotient({4,5}*2^x2, 4)	// between x1 and (5/4)*x1
	))));
	// check whether x2 is the root
	y1 := x2^s;
	If(
		y1=n,
		x1 := x2,
		// x2 is not a root, so continue as before with x1
		y1 := x1^s	// henceforth, y1 is always x1^s
	);
	// Newton iteration combined with bisection
	While(y1 < n)
	[
//	Echo({x1, x2});
		x'new := Quotient(x1*((s-1)*y1+(s+1)*n), (s+1)*y1+(s-1)*n) + 1;	// add 1 because the floating-point value undershoots
		If(
			x'new < Quotient(x1+x2, 2),
			// x'new did not reach the midpoint, need to check progress
			If(
				Quotient(x1+x2, 2)^s <= n,
				// Newton's iteration is not making good progress, so leave x2 in place and update x1 by bisection
				x'new := Quotient(x1+x2, 2),
				// Newton's iteration knows what it is doing. Update x2 by bisection
				x2 := Quotient(x1+x2, 2)
			)
			// else, x'new reached the midpoint, good progress, continue
		);
		x1 := x'new;
		y1 := x1^s;
	];
	If(y1=n, x1, x1-1);	// subtract 1 if we overshot
];
*/

%/mathpiper



%mathpiper_docs,name="IntNthRoot",categories="User Functions;Numbers (Operations)"
*CMD IntNthRoot --- integer part of $n$-th root
*STD
*CALL
	IntNthRoot(x, n)

*PARMS

{x}, {n} -- positive integers

*DESC

{IntNthRoot} calculates the integer part of the $n$-th root of $x$. The algorithm uses only 
integer math and may be faster than computing $x^(1/n)$ with floating-point and rounding.

This function is used to test numbers for prime powers.

*E.G.
In> IntNthRoot(65537^111, 37)
Result: 281487861809153;

*SEE IntLog, PowerN, IsPrimePower
%/mathpiper_docs