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