Blame mpf/sqrt.c

Packit 5c3484
/* mpf_sqrt -- Compute the square root of a float.
Packit 5c3484
Packit 5c3484
Copyright 1993, 1994, 1996, 2000, 2001, 2004, 2005, 2012 Free Software
Packit 5c3484
Foundation, Inc.
Packit 5c3484
Packit 5c3484
This file is part of the GNU MP Library.
Packit 5c3484
Packit 5c3484
The GNU MP Library is free software; you can redistribute it and/or modify
Packit 5c3484
it under the terms of either:
Packit 5c3484
Packit 5c3484
  * the GNU Lesser General Public License as published by the Free
Packit 5c3484
    Software Foundation; either version 3 of the License, or (at your
Packit 5c3484
    option) any later version.
Packit 5c3484
Packit 5c3484
or
Packit 5c3484
Packit 5c3484
  * the GNU General Public License as published by the Free Software
Packit 5c3484
    Foundation; either version 2 of the License, or (at your option) any
Packit 5c3484
    later version.
Packit 5c3484
Packit 5c3484
or both in parallel, as here.
Packit 5c3484
Packit 5c3484
The GNU MP Library is distributed in the hope that it will be useful, but
Packit 5c3484
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit 5c3484
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
Packit 5c3484
for more details.
Packit 5c3484
Packit 5c3484
You should have received copies of the GNU General Public License and the
Packit 5c3484
GNU Lesser General Public License along with the GNU MP Library.  If not,
Packit 5c3484
see https://www.gnu.org/licenses/.  */
Packit 5c3484
Packit 5c3484
#include <stdio.h> /* for NULL */
Packit 5c3484
#include "gmp.h"
Packit 5c3484
#include "gmp-impl.h"
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* As usual, the aim is to produce PREC(r) limbs of result, with the high
Packit 5c3484
   limb non-zero.  This is accomplished by applying mpn_sqrtrem to either
Packit 5c3484
   2*prec or 2*prec-1 limbs, both such sizes resulting in prec limbs.
Packit 5c3484
Packit 5c3484
   The choice between 2*prec or 2*prec-1 limbs is based on the input
Packit 5c3484
   exponent.  With b=2^GMP_NUMB_BITS the limb base then we can think of
Packit 5c3484
   effectively taking out a factor b^(2k), for suitable k, to get to an
Packit 5c3484
   integer input of the desired size ready for mpn_sqrtrem.  It must be an
Packit 5c3484
   even power taken out, ie. an even number of limbs, so the square root
Packit 5c3484
   gives factor b^k and the radix point is still on a limb boundary.  So if
Packit 5c3484
   EXP(r) is even we'll get an even number of input limbs 2*prec, or if
Packit 5c3484
   EXP(r) is odd we get an odd number 2*prec-1.
Packit 5c3484
Packit 5c3484
   Further limbs below the 2*prec or 2*prec-1 used don't affect the result
Packit 5c3484
   and are simply truncated.  This can be seen by considering an integer x,
Packit 5c3484
   with s=floor(sqrt(x)).  s is the unique integer satisfying s^2 <= x <
Packit 5c3484
   (s+1)^2.  Notice that adding a fraction part to x (ie. some further bits)
Packit 5c3484
   doesn't change the inequality, s remains the unique solution.  Working
Packit 5c3484
   suitable factors of 2 into this argument lets it apply to an intended
Packit 5c3484
   precision at any position for any x, not just the integer binary point.
Packit 5c3484
Packit 5c3484
   If the input is smaller than 2*prec or 2*prec-1, then we just pad with
Packit 5c3484
   zeros, that of course being our usual interpretation of short inputs.
Packit 5c3484
   The effect is to extend the root beyond the size of the input (for
Packit 5c3484
   instance into fractional limbs if u is an integer).  */
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
mpf_sqrt (mpf_ptr r, mpf_srcptr u)
Packit 5c3484
{
Packit 5c3484
  mp_size_t usize;
Packit 5c3484
  mp_ptr up, tp;
Packit 5c3484
  mp_size_t prec, tsize;
Packit 5c3484
  mp_exp_t uexp, expodd;
Packit 5c3484
  TMP_DECL;
Packit 5c3484
Packit 5c3484
  usize = u->_mp_size;
Packit 5c3484
  if (UNLIKELY (usize <= 0))
Packit 5c3484
    {
Packit 5c3484
      if (usize < 0)
Packit 5c3484
        SQRT_OF_NEGATIVE;
Packit 5c3484
      r->_mp_size = 0;
Packit 5c3484
      r->_mp_exp = 0;
Packit 5c3484
      return;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  TMP_MARK;
Packit 5c3484
Packit 5c3484
  uexp = u->_mp_exp;
Packit 5c3484
  prec = r->_mp_prec;
Packit 5c3484
  up = u->_mp_d;
Packit 5c3484
Packit 5c3484
  expodd = (uexp & 1);
Packit 5c3484
  tsize = 2 * prec - expodd;
Packit 5c3484
  r->_mp_size = prec;
Packit 5c3484
  r->_mp_exp = (uexp + expodd) / 2;    /* ceil(uexp/2) */
Packit 5c3484
Packit 5c3484
  /* root size is ceil(tsize/2), this will be our desired "prec" limbs */
Packit 5c3484
  ASSERT ((tsize + 1) / 2 == prec);
Packit 5c3484
Packit 5c3484
  tp = TMP_ALLOC_LIMBS (tsize);
Packit 5c3484
Packit 5c3484
  if (usize > tsize)
Packit 5c3484
    {
Packit 5c3484
      up += usize - tsize;
Packit 5c3484
      usize = tsize;
Packit 5c3484
      MPN_COPY (tp, up, tsize);
Packit 5c3484
    }
Packit 5c3484
  else
Packit 5c3484
    {
Packit 5c3484
      MPN_ZERO (tp, tsize - usize);
Packit 5c3484
      MPN_COPY (tp + (tsize - usize), up, usize);
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  mpn_sqrtrem (r->_mp_d, NULL, tp, tsize);
Packit 5c3484
Packit 5c3484
  TMP_FREE;
Packit 5c3484
}