/*============================================================================= This file is part of FLINT. FLINT is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. FLINT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with FLINT; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =============================================================================*/ /****************************************************************************** Copyright (C) 2012 William Hart ******************************************************************************/ #define ulong ulongxx /* interferes with system includes */ #include #include #undef ulong #define ulong mp_limb_t #include #include "flint.h" #include "ulong_extras.h" slong n_sqrtmod_2pow(mp_limb_t ** sqrt, mp_limb_t a, slong exp) { mp_limb_t r = (a & 1); mp_limb_t * s; if (exp == 0) /* special case for sqrt of 0 mod 1 */ { *sqrt = flint_malloc(sizeof(mp_limb_t)); (*sqrt)[0] = 0; return 1; } if (exp == 1) /* special case mod 2 */ { *sqrt = flint_malloc(sizeof(mp_limb_t)); if (r) (*sqrt)[0] = 1; else (*sqrt)[0] = 0; return 1; } if (exp == 2) /* special case mod 4 */ { r = (a & 3); if (r < 2) /* 0, 1 mod 4 */ { *sqrt = flint_malloc(sizeof(mp_limb_t)*2); (*sqrt)[0] = r; (*sqrt)[1] = r + 2; return 2; } else /* 2, 3 mod 4 */ { *sqrt = NULL; return 0; } } if (r) /* a is odd */ { mp_limb_t roots[2]; slong i, ex, pow; if ((a & 7) != 1) /* check square root exists */ { *sqrt = NULL; return 0; } roots[0] = 1; /* one of each pair of square roots mod 8 */ roots[1] = 3; pow = 8; for (ex = 3; ex < exp; ex++, pow *= 2) /* lift roots */ { i = 0; r = roots[0]; if (((r*r) & (2*pow - 1)) == (a & (2*pow - 1))) roots[i++] = r; r = pow - r; if (((r*r) & (2*pow - 1)) == (a & (2*pow - 1))) { roots[i++] = r; if (i == 2) continue; } r = roots[1]; if (((r*r) & (2*pow - 1)) == (a & (2*pow - 1))) { roots[i++] = r; if (i == 2) continue; } r = pow - r; roots[i] = r; } *sqrt = flint_malloc(sizeof(mp_limb_t)*4); (*sqrt)[0] = roots[0]; /* write out both pairs of roots */ (*sqrt)[1] = pow - roots[0]; (*sqrt)[2] = roots[1]; (*sqrt)[3] = pow - roots[1]; return 4; } else /* a is even */ { slong i, k, num, pow; for (k = 2; k <= exp; k++) /* find highest power of 2 dividing a */ { if (a & ((UWORD(1)<