xref: /dragonfly/contrib/gmp/mpz/sqrtrem.c (revision 86d7f5d3)
1*86d7f5d3SJohn Marino /* mpz_sqrtrem(root,rem,x) -- Set ROOT to floor(sqrt(X)) and REM
2*86d7f5d3SJohn Marino    to the remainder, i.e. X - ROOT**2.
3*86d7f5d3SJohn Marino 
4*86d7f5d3SJohn Marino Copyright 1991, 1993, 1994, 1996, 2000, 2001, 2005 Free Software Foundation,
5*86d7f5d3SJohn Marino Inc.
6*86d7f5d3SJohn Marino 
7*86d7f5d3SJohn Marino This file is part of the GNU MP Library.
8*86d7f5d3SJohn Marino 
9*86d7f5d3SJohn Marino The GNU MP Library is free software; you can redistribute it and/or modify
10*86d7f5d3SJohn Marino it under the terms of the GNU Lesser General Public License as published by
11*86d7f5d3SJohn Marino the Free Software Foundation; either version 3 of the License, or (at your
12*86d7f5d3SJohn Marino option) any later version.
13*86d7f5d3SJohn Marino 
14*86d7f5d3SJohn Marino The GNU MP Library is distributed in the hope that it will be useful, but
15*86d7f5d3SJohn Marino WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16*86d7f5d3SJohn Marino or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
17*86d7f5d3SJohn Marino License for more details.
18*86d7f5d3SJohn Marino 
19*86d7f5d3SJohn Marino You should have received a copy of the GNU Lesser General Public License
20*86d7f5d3SJohn Marino along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
21*86d7f5d3SJohn Marino 
22*86d7f5d3SJohn Marino #include <stdio.h> /* for NULL */
23*86d7f5d3SJohn Marino #include "gmp.h"
24*86d7f5d3SJohn Marino #include "gmp-impl.h"
25*86d7f5d3SJohn Marino #ifdef BERKELEY_MP
26*86d7f5d3SJohn Marino #include "mp.h"
27*86d7f5d3SJohn Marino #endif
28*86d7f5d3SJohn Marino 
29*86d7f5d3SJohn Marino void
30*86d7f5d3SJohn Marino #ifndef BERKELEY_MP
mpz_sqrtrem(mpz_ptr root,mpz_ptr rem,mpz_srcptr op)31*86d7f5d3SJohn Marino mpz_sqrtrem (mpz_ptr root, mpz_ptr rem, mpz_srcptr op)
32*86d7f5d3SJohn Marino #else /* BERKELEY_MP */
33*86d7f5d3SJohn Marino msqrt (mpz_srcptr op, mpz_ptr root, mpz_ptr rem)
34*86d7f5d3SJohn Marino #endif /* BERKELEY_MP */
35*86d7f5d3SJohn Marino {
36*86d7f5d3SJohn Marino   mp_size_t op_size, root_size, rem_size;
37*86d7f5d3SJohn Marino   mp_ptr root_ptr, op_ptr;
38*86d7f5d3SJohn Marino   mp_ptr free_me = NULL;
39*86d7f5d3SJohn Marino   mp_size_t free_me_size;
40*86d7f5d3SJohn Marino   TMP_DECL;
41*86d7f5d3SJohn Marino 
42*86d7f5d3SJohn Marino   TMP_MARK;
43*86d7f5d3SJohn Marino   op_size = op->_mp_size;
44*86d7f5d3SJohn Marino   if (op_size <= 0)
45*86d7f5d3SJohn Marino     {
46*86d7f5d3SJohn Marino       if (op_size < 0)
47*86d7f5d3SJohn Marino         SQRT_OF_NEGATIVE;
48*86d7f5d3SJohn Marino       SIZ(root) = 0;
49*86d7f5d3SJohn Marino       SIZ(rem) = 0;
50*86d7f5d3SJohn Marino       return;
51*86d7f5d3SJohn Marino     }
52*86d7f5d3SJohn Marino 
53*86d7f5d3SJohn Marino   if (rem->_mp_alloc < op_size)
54*86d7f5d3SJohn Marino     _mpz_realloc (rem, op_size);
55*86d7f5d3SJohn Marino 
56*86d7f5d3SJohn Marino   /* The size of the root is accurate after this simple calculation.  */
57*86d7f5d3SJohn Marino   root_size = (op_size + 1) / 2;
58*86d7f5d3SJohn Marino 
59*86d7f5d3SJohn Marino   root_ptr = root->_mp_d;
60*86d7f5d3SJohn Marino   op_ptr = op->_mp_d;
61*86d7f5d3SJohn Marino 
62*86d7f5d3SJohn Marino   if (root->_mp_alloc < root_size)
63*86d7f5d3SJohn Marino     {
64*86d7f5d3SJohn Marino       if (root_ptr == op_ptr)
65*86d7f5d3SJohn Marino 	{
66*86d7f5d3SJohn Marino 	  free_me = root_ptr;
67*86d7f5d3SJohn Marino 	  free_me_size = root->_mp_alloc;
68*86d7f5d3SJohn Marino 	}
69*86d7f5d3SJohn Marino       else
70*86d7f5d3SJohn Marino 	(*__gmp_free_func) (root_ptr, root->_mp_alloc * BYTES_PER_MP_LIMB);
71*86d7f5d3SJohn Marino 
72*86d7f5d3SJohn Marino       root->_mp_alloc = root_size;
73*86d7f5d3SJohn Marino       root_ptr = (mp_ptr) (*__gmp_allocate_func) (root_size * BYTES_PER_MP_LIMB);
74*86d7f5d3SJohn Marino       root->_mp_d = root_ptr;
75*86d7f5d3SJohn Marino     }
76*86d7f5d3SJohn Marino   else
77*86d7f5d3SJohn Marino     {
78*86d7f5d3SJohn Marino       /* Make OP not overlap with ROOT.  */
79*86d7f5d3SJohn Marino       if (root_ptr == op_ptr)
80*86d7f5d3SJohn Marino 	{
81*86d7f5d3SJohn Marino 	  /* ROOT and OP are identical.  Allocate temporary space for OP.  */
82*86d7f5d3SJohn Marino 	  op_ptr = TMP_ALLOC_LIMBS (op_size);
83*86d7f5d3SJohn Marino 	  /* Copy to the temporary space.  Hack: Avoid temporary variable
84*86d7f5d3SJohn Marino 	     by using ROOT_PTR.  */
85*86d7f5d3SJohn Marino 	  MPN_COPY (op_ptr, root_ptr, op_size);
86*86d7f5d3SJohn Marino 	}
87*86d7f5d3SJohn Marino     }
88*86d7f5d3SJohn Marino 
89*86d7f5d3SJohn Marino   rem_size = mpn_sqrtrem (root_ptr, rem->_mp_d, op_ptr, op_size);
90*86d7f5d3SJohn Marino 
91*86d7f5d3SJohn Marino   root->_mp_size = root_size;
92*86d7f5d3SJohn Marino 
93*86d7f5d3SJohn Marino   /* Write remainder size last, to enable us to define this function to
94*86d7f5d3SJohn Marino      give only the square root remainder, if the user calls if with
95*86d7f5d3SJohn Marino      ROOT == REM.  */
96*86d7f5d3SJohn Marino   rem->_mp_size = rem_size;
97*86d7f5d3SJohn Marino 
98*86d7f5d3SJohn Marino   if (free_me != NULL)
99*86d7f5d3SJohn Marino     (*__gmp_free_func) (free_me, free_me_size * BYTES_PER_MP_LIMB);
100*86d7f5d3SJohn Marino   TMP_FREE;
101*86d7f5d3SJohn Marino }
102