/*
Copyright (C) 2010 Sebastian Pancratz
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 .
*/
#include
#include "flint.h"
#include "fmpz.h"
#include "fmpz_vec.h"
#include "fmpz_poly.h"
void
_fmpz_poly_pow_trunc(fmpz * res, const fmpz * poly, ulong e, slong n)
{
ulong bit = ~((~UWORD(0)) >> 1);
fmpz *v = _fmpz_vec_init(n);
fmpz *R, *S, *T;
/*
Set bits to the bitmask with a 1 one place lower than the msb of e
*/
while ((bit & e) == UWORD(0))
bit >>= 1;
bit >>= 1;
/*
Trial run without any polynomial arithmetic to determine the parity
of the number of swaps; then set R and S accordingly
*/
{
unsigned int swaps = 0U;
ulong bit2 = bit;
if ((bit2 & e))
swaps = ~swaps;
while (bit2 >>= 1)
if ((bit2 & e) == UWORD(0))
swaps = ~swaps;
if (swaps == 0U)
{
R = res;
S = v;
}
else
{
R = v;
S = res;
}
}
/*
We unroll the first step of the loop, referring to {poly, n}
*/
_fmpz_poly_sqrlow(R, poly, n, n);
if ((bit & e))
{
_fmpz_poly_mullow(S, R, n, poly, n, n);
T = R;
R = S;
S = T;
}
while ((bit >>= 1))
{
if ((bit & e))
{
_fmpz_poly_sqrlow(S, R, n, n);
_fmpz_poly_mullow(R, S, n, poly, n, n);
}
else
{
_fmpz_poly_sqrlow(S, R, n, n);
T = R;
R = S;
S = T;
}
}
_fmpz_vec_clear(v, n);
}
void
fmpz_poly_pow_trunc(fmpz_poly_t res, const fmpz_poly_t poly, ulong e, slong n)
{
fmpz * copy;
int clear;
slong i, len;
if (n == 0)
{
fmpz_poly_zero(res);
return;
}
if (e == 0)
{
fmpz_poly_set_ui(res, 1);
return;
}
/* Set len to the length of poly mod x^n */
len = FLINT_MIN(n, poly->length);
for (--len; (len >= 0) && !poly->coeffs[len]; --len) ;
++len;
if ((len < 2) | (e < 3))
{
if (len == 0)
fmpz_poly_zero(res);
else if (len == 1)
{
fmpz_poly_fit_length(res, 1);
fmpz_pow_ui(res->coeffs, poly->coeffs, e);
_fmpz_poly_set_length(res, 1);
}
else if (e == 1)
{
if (res != poly)
{
fmpz_poly_fit_length(res, len);
_fmpz_vec_set(res->coeffs, poly->coeffs, len);
_fmpz_poly_set_length(res, len);
}
else
fmpz_poly_truncate(res, len);
}
else /* e == 2 */
fmpz_poly_sqrlow(res, poly, n);
return;
}
if (poly->length >= n)
{
copy = poly->coeffs;
clear = 0;
}
else
{
copy = (fmpz *) flint_malloc(n * sizeof(fmpz));
for (i = 0; i < poly->length; i++)
copy[i] = poly->coeffs[i];
flint_mpn_zero((mp_ptr) copy + poly->length, n - poly->length);
clear = 1;
}
if (res != poly)
{
fmpz_poly_fit_length(res, n);
_fmpz_poly_pow_trunc(res->coeffs, copy, e, n);
}
else
{
fmpz_poly_t t;
fmpz_poly_init2(t, n);
_fmpz_poly_pow_trunc(t->coeffs, copy, e, n);
fmpz_poly_swap(res, t);
fmpz_poly_clear(t);
}
_fmpz_poly_set_length(res, n);
_fmpz_poly_normalise(res);
if (clear)
flint_free(copy);
}