186d7f5d3SJohn Marino /* mpf_sqrt_ui -- Compute the square root of an unsigned integer.
286d7f5d3SJohn Marino
386d7f5d3SJohn Marino Copyright 1993, 1994, 1996, 2000, 2001, 2004, 2005 Free Software Foundation,
486d7f5d3SJohn Marino Inc.
586d7f5d3SJohn Marino
686d7f5d3SJohn Marino This file is part of the GNU MP Library.
786d7f5d3SJohn Marino
886d7f5d3SJohn Marino The GNU MP Library is free software; you can redistribute it and/or modify
986d7f5d3SJohn Marino it under the terms of the GNU Lesser General Public License as published by
1086d7f5d3SJohn Marino the Free Software Foundation; either version 3 of the License, or (at your
1186d7f5d3SJohn Marino option) any later version.
1286d7f5d3SJohn Marino
1386d7f5d3SJohn Marino The GNU MP Library is distributed in the hope that it will be useful, but
1486d7f5d3SJohn Marino WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
1586d7f5d3SJohn Marino or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
1686d7f5d3SJohn Marino License for more details.
1786d7f5d3SJohn Marino
1886d7f5d3SJohn Marino You should have received a copy of the GNU Lesser General Public License
1986d7f5d3SJohn Marino along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
2086d7f5d3SJohn Marino
2186d7f5d3SJohn Marino #include <stdio.h> /* for NULL */
2286d7f5d3SJohn Marino #include "gmp.h"
2386d7f5d3SJohn Marino #include "gmp-impl.h"
2486d7f5d3SJohn Marino
2586d7f5d3SJohn Marino
2686d7f5d3SJohn Marino /* As usual the aim is to produce PREC(r) limbs of result with the high limb
2786d7f5d3SJohn Marino non-zero. That high limb will end up floor(sqrt(u)), and limbs below are
2886d7f5d3SJohn Marino produced by padding the input with zeros, two for each desired result
2986d7f5d3SJohn Marino limb, being 2*(prec-1) for a total 2*prec-1 limbs passed to mpn_sqrtrem.
3086d7f5d3SJohn Marino The way mpn_sqrtrem calculates floor(sqrt(x)) ensures the root is correct
3186d7f5d3SJohn Marino to the intended accuracy, ie. truncated to prec limbs.
3286d7f5d3SJohn Marino
3386d7f5d3SJohn Marino With nails, u might be two limbs, in which case a total 2*prec limbs is
3486d7f5d3SJohn Marino passed to mpn_sqrtrem (still giving a prec limb result). If uhigh is
3586d7f5d3SJohn Marino zero we adjust back to 2*prec-1, since mpn_sqrtrem requires the high
3686d7f5d3SJohn Marino non-zero. 2*prec limbs are always allocated, even when uhigh is zero, so
3786d7f5d3SJohn Marino the store of uhigh can be done without a conditional.
3886d7f5d3SJohn Marino
3986d7f5d3SJohn Marino u==0 is a special case so the rest of the code can assume the result is
4086d7f5d3SJohn Marino non-zero (ie. will have a non-zero high limb on the result).
4186d7f5d3SJohn Marino
4286d7f5d3SJohn Marino Not done:
4386d7f5d3SJohn Marino
4486d7f5d3SJohn Marino No attempt is made to identify perfect squares. It's considered this can
4586d7f5d3SJohn Marino be left to an application if it might occur with any frequency. As it
4686d7f5d3SJohn Marino stands, mpn_sqrtrem does its normal amount of work on a perfect square
4786d7f5d3SJohn Marino followed by zero limbs, though of course only an mpn_sqrtrem1 would be
4886d7f5d3SJohn Marino actually needed. We also end up leaving our mpf result with lots of low
4986d7f5d3SJohn Marino trailing zeros, slowing down subsequent operations.
5086d7f5d3SJohn Marino
5186d7f5d3SJohn Marino We're not aware of any optimizations that can be made using the fact the
5286d7f5d3SJohn Marino input has lots of trailing zeros (apart from the perfect square
5386d7f5d3SJohn Marino case). */
5486d7f5d3SJohn Marino
5586d7f5d3SJohn Marino
5686d7f5d3SJohn Marino /* 1 if we (might) need two limbs for u */
5786d7f5d3SJohn Marino #define U2 (GMP_NUMB_BITS < BITS_PER_ULONG)
5886d7f5d3SJohn Marino
5986d7f5d3SJohn Marino void
mpf_sqrt_ui(mpf_ptr r,unsigned long int u)6086d7f5d3SJohn Marino mpf_sqrt_ui (mpf_ptr r, unsigned long int u)
6186d7f5d3SJohn Marino {
6286d7f5d3SJohn Marino mp_size_t rsize, zeros;
6386d7f5d3SJohn Marino mp_ptr tp;
6486d7f5d3SJohn Marino mp_size_t prec;
6586d7f5d3SJohn Marino TMP_DECL;
6686d7f5d3SJohn Marino
6786d7f5d3SJohn Marino if (UNLIKELY (u == 0))
6886d7f5d3SJohn Marino {
6986d7f5d3SJohn Marino r->_mp_size = 0;
7086d7f5d3SJohn Marino r->_mp_exp = 0;
7186d7f5d3SJohn Marino return;
7286d7f5d3SJohn Marino }
7386d7f5d3SJohn Marino
7486d7f5d3SJohn Marino TMP_MARK;
7586d7f5d3SJohn Marino
7686d7f5d3SJohn Marino prec = r->_mp_prec;
7786d7f5d3SJohn Marino zeros = 2 * prec - 2;
7886d7f5d3SJohn Marino rsize = zeros + 1 + U2;
7986d7f5d3SJohn Marino
8086d7f5d3SJohn Marino tp = TMP_ALLOC_LIMBS (rsize);
8186d7f5d3SJohn Marino
8286d7f5d3SJohn Marino MPN_ZERO (tp, zeros);
8386d7f5d3SJohn Marino tp[zeros] = u & GMP_NUMB_MASK;
8486d7f5d3SJohn Marino
8586d7f5d3SJohn Marino #if U2
8686d7f5d3SJohn Marino {
8786d7f5d3SJohn Marino mp_limb_t uhigh = u >> GMP_NUMB_BITS;
8886d7f5d3SJohn Marino tp[zeros + 1] = uhigh;
8986d7f5d3SJohn Marino rsize -= (uhigh == 0);
9086d7f5d3SJohn Marino }
9186d7f5d3SJohn Marino #endif
9286d7f5d3SJohn Marino
9386d7f5d3SJohn Marino mpn_sqrtrem (r->_mp_d, NULL, tp, rsize);
9486d7f5d3SJohn Marino
9586d7f5d3SJohn Marino r->_mp_size = prec;
9686d7f5d3SJohn Marino r->_mp_exp = 1;
9786d7f5d3SJohn Marino TMP_FREE;
9886d7f5d3SJohn Marino }
99