%mathpiper,def="MathSqrtFloat"

/** This file contains routines for numerical evaluation of elementary functions:
 *  PowerN, ExpN, SinN etc.
 *  It is assumed that the arguments are real (not complex) floating-point or integer numbers. (The {InNumericMode()} flag does not have to be set.)
 *  The result is an exact integer or a floating-point number correct to BuiltinPrecisionGet() digits.
 *
 *  If a better optimized version of these functions is available through the kernel,
 *  then the kernel version will automatically shadow these functions.
 *  These implementations are not necessarily the best optimized versions.
 */

// This function is *only* for float and positive A!
// The answer is only obtained at the current precision.
MathSqrtFloat(_A) <--
[
	Local(bitshift, a0, x0, x0sq, targetbits, subtargetbits, gotbits, targetprec);
	bitshift := ShiftRight(MathBitCount(A)-1,1);
	// this is how many bits of precision we need
	targetprec := BuiltinPrecisionGet();
	// argument reduction: a0 is between 1 and 4 and has the full target precision
	a0 := MathMul2Exp(A, -bitshift*2);	// this bit shift would be wrong for integer A
	BuiltinPrecisionSet(10);	// enough to compute at this point
	// cannot get more target bits than 1 + (the bits in A)
	// if this is less than the requested precision, the result will be silently less precise, but c'est la vie
	targetbits := Minimum(DigitsToBits(targetprec, 10), 1+GetExactBitsN(A));
	// initial approximation
	x0 := DivideN(14+22*a0, 31+5*a0);
	// this approximation gives at least 7 bits (relative error < 0.005) of Sqrt(a0) for 1 <= a0 <= 4
	gotbits := 7;
	// find the conditions for the last 2 iterations to be done in almost optimal precision
	subtargetbits := QuotientN(targetbits+8, 9);
	If(gotbits >= subtargetbits, subtargetbits := QuotientN(targetbits+2, 3));
	If(gotbits >= subtargetbits, subtargetbits := targetbits*4);
//	Echo("debug: subtargetbits=", subtargetbits, "a0=", a0, "targetbits=", targetbits, "bitshift=", bitshift, "targetprec=", targetprec);
	// now perform Halley iterations until we get at least subtargetbits, then start with subtargetbits and perform further Halley iterations
	While(gotbits < targetbits)
	[
		gotbits := 3*gotbits+1;	// Halley iteration; get 3n+2 bits, allow 1 bit for roundoff
		// check for suboptimal last iterations
		If(gotbits >= subtargetbits,
		[	// it could be very suboptimal to continue with our value of gotbits, so we curb precision for the last 2 iterations which dominate the calculation time at high precision
			gotbits := subtargetbits;
			subtargetbits := targetbits*4;	// make sure that the above condition never becomes true again
		]);
		BuiltinPrecisionSet(BitsToDigits(gotbits, 10)+2);	// guard digits
		x0 := SetExactBitsN(x0, gotbits+6);	// avoid roundoff
		x0sq := MultiplyN(x0, x0);
// this gives too much roundoff error		x0 := MultiplyN(x0, DivideN(3*a0+x0sq, a0+3*x0sq));
// rather use this equivalent formula:
		x0 := AddN(x0, MultiplyN(x0*2, DivideN(a0-x0sq, a0+3*x0sq)));
//		Echo("debug: ", gotbits, x0, GetExactBitsN(x0), BuiltinPrecisionGet());
	];
	// avoid truncating a precise result in x0 by calling BuiltinPrecisionSet() too soon
	x0 := SetExactBitsN(MathMul2Exp(x0, bitshift), gotbits);
	BuiltinPrecisionSet(targetprec);
//	Echo("debug: answer=", x0);
	x0;
];

%/mathpiper