/*
Copyright (C) 2012 William Hart
This file is part of FLINT.
FLINT is free software: you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version. See .
*/
#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)<