%mathpiper,def="BisectSqrt"

/** 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.
 */

//{BisectSqrt(N)} computes the integer part of $ Sqrt(N) $ for integer $N$.
// BisectSqrt() works only on integers
	//sqrt(1) = 1, sqrt(0) = 0
10 # BisectSqrt(0) <-- 0;
10 # BisectSqrt(1) <-- 1;

20 # BisectSqrt(N_IsPositiveInteger) <--
[
  Local(l2,u,v,u2,v2,uv2,n);

  // Find highest set bit, l2
  u  := N;
  l2 := MathBitCount(u)-1;

  // 1<<(l2/2) now would be a good under estimate
  // for the square root. 1<<(l2/2) is definitely
  // set in the result. Also it is the highest
  // set bit.
  l2 := l2>>1;

  // initialize u and u2 (u2==u^2).
  u  := 1 << l2;
  u2 := u << l2;

  // Now for each lower bit:
  While( l2 != 0 )
  [
 	 l2--;
     // Get that bit in v, and v2 == v^2.
      v  := 1<<l2;
      v2 := v<<l2;

      // uv2 == 2*u*v, where 2==1<<1, and
      // v==1<<l2, thus 2*u*v ==
      // (1<<1)*u*(1<<l2) == u<<(l2+1)
      uv2 := u<<(l2 + 1);

      // n = (u+v)^2  = u^2 + 2*u*v + v^2
      //   = u2+uv2+v2
       n := u2 + uv2 + v2;

      // if n (possible new best estimate for
      // sqrt(N)^2 is smaller than N, then the
      // bit l2 is set in the result, and
      // add v to u.
      if( n <= N )
      [
	u  := u+v;  // u <- u+v
	u2 := n;    // u^2 <- u^2 + 2*u*v + v^2
      ];
    ];
    u; // return result, accumulated in u.
];

%/mathpiper