186 lines
5.5 KiB
C
186 lines
5.5 KiB
C
|
/*=============================================================================
|
||
|
|
||
|
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) 2010 William Hart
|
||
|
|
||
|
******************************************************************************/
|
||
|
|
||
|
#include <gmp.h>
|
||
|
#include "flint.h"
|
||
|
#include "fmpz.h"
|
||
|
|
||
|
int
|
||
|
fmpz_bit_pack(mp_ptr arr, mp_bitcnt_t shift, mp_bitcnt_t bits,
|
||
|
const fmpz_t coeff, int negate, int borrow)
|
||
|
{
|
||
|
mp_limb_t save = arr[0];
|
||
|
fmpz c = *coeff;
|
||
|
int sign = fmpz_sgn(coeff);
|
||
|
mp_limb_t cy;
|
||
|
ulong limbs = (shift + bits) / FLINT_BITS;
|
||
|
ulong rem_bits = (shift + bits) % FLINT_BITS;
|
||
|
mp_limb_t mask;
|
||
|
ulong size;
|
||
|
|
||
|
if (sign == 0) /* special case, deal with zero (store -borrow) */
|
||
|
{
|
||
|
if (borrow)
|
||
|
{
|
||
|
/* store -1 shifted and add save back in */
|
||
|
arr[0] = ((~(mp_limb_t) 0) << shift) + save;
|
||
|
|
||
|
/* com remaining limbs */
|
||
|
if (limbs > 1)
|
||
|
flint_mpn_store(arr + 1, limbs - 1, ~(mp_limb_t) 0);
|
||
|
|
||
|
/* com remaining bits */
|
||
|
if (limbs)
|
||
|
{
|
||
|
if (rem_bits)
|
||
|
arr[limbs] = (((mp_limb_t) 1) << rem_bits) - (mp_limb_t) 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* mask off final limb */
|
||
|
mask = (((mp_limb_t) 1) << rem_bits) - (mp_limb_t) 1;
|
||
|
arr[limbs] &= mask;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
return borrow;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Let |c| = b. If c is -ve and negate == 0 or c is positive and negate is 1
|
||
|
we want -b - borrow.
|
||
|
|
||
|
If c is +ve and negate is 0 or c is negative and negate == 1, we want
|
||
|
b - borrow.
|
||
|
*/
|
||
|
if ((sign ^ negate) < 0) /* -b - borrow = com(b) + 1 - borrow */
|
||
|
{
|
||
|
if (!COEFF_IS_MPZ(c))
|
||
|
{
|
||
|
/* compute d = -b - borrow */
|
||
|
mp_limb_t d = (c < WORD(0) ? c - borrow : -c - borrow);
|
||
|
|
||
|
/* store d << shift and add save back into place */
|
||
|
arr[0] = (d << shift) + save;
|
||
|
|
||
|
/* store carry from d<<shift and com remaining bits of second limb */
|
||
|
if (limbs)
|
||
|
{
|
||
|
if (shift)
|
||
|
arr[1] =
|
||
|
(d >> (FLINT_BITS - shift)) +
|
||
|
((~(mp_limb_t) 0) << shift);
|
||
|
else
|
||
|
arr[1] = ~(mp_limb_t) 0;
|
||
|
}
|
||
|
|
||
|
size = 2;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
__mpz_struct * ptr = COEFF_TO_PTR(c);
|
||
|
size = FLINT_ABS(ptr->_mp_size);
|
||
|
|
||
|
/* complement coefficient into arr */
|
||
|
mpn_com_n(arr, ptr->_mp_d, size);
|
||
|
|
||
|
/* deal with +1 - borrow */
|
||
|
if (!borrow)
|
||
|
mpn_add_1(arr, arr, size, 1); /* cannot be a carry, else we com'd 0 */
|
||
|
|
||
|
/* shift into place */
|
||
|
if (shift)
|
||
|
{
|
||
|
cy = mpn_lshift(arr, arr, size, shift);
|
||
|
if (limbs + (rem_bits != 0) > size)
|
||
|
arr[size++] = ((~(mp_limb_t) 0) << shift) + cy;
|
||
|
}
|
||
|
|
||
|
/* add back in saved bits from start of field */
|
||
|
arr[0] += save;
|
||
|
}
|
||
|
|
||
|
if (limbs >= size)
|
||
|
{
|
||
|
/* com any additional limbs */
|
||
|
if (limbs > size)
|
||
|
flint_mpn_store(arr + size, limbs - size, ~(mp_limb_t) 0);
|
||
|
|
||
|
/* com remaining bits */
|
||
|
if (rem_bits)
|
||
|
arr[limbs] = (((mp_limb_t) 1) << rem_bits) - (mp_limb_t) 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* mask off final limb */
|
||
|
mask = (((mp_limb_t) 1) << rem_bits) - (mp_limb_t) 1;
|
||
|
arr[limbs] &= mask;
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
else /* b - borrow */
|
||
|
{
|
||
|
if (!COEFF_IS_MPZ(c))
|
||
|
{
|
||
|
/* compute d = b - borrow */
|
||
|
mp_limb_t d = (c < WORD(0) ? -c - borrow : c - borrow);
|
||
|
|
||
|
/* store d<<shift and add save back into place */
|
||
|
arr[0] = (d << shift) + save;
|
||
|
|
||
|
/* store carry from d<<shift */
|
||
|
if (limbs + (rem_bits != 0) > 1)
|
||
|
{
|
||
|
if (shift)
|
||
|
arr[1] = (d >> (FLINT_BITS - shift));
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
__mpz_struct *ptr = COEFF_TO_PTR(c);
|
||
|
size = FLINT_ABS(ptr->_mp_size);
|
||
|
|
||
|
/* shift into place */
|
||
|
if (shift)
|
||
|
{
|
||
|
cy = mpn_lshift(arr, ptr->_mp_d, size, shift);
|
||
|
if (cy)
|
||
|
arr[size++] = cy;
|
||
|
}
|
||
|
else
|
||
|
flint_mpn_copyi(arr, ptr->_mp_d, size);
|
||
|
|
||
|
/* deal with - borrow */
|
||
|
if (borrow)
|
||
|
mpn_sub_1(arr, arr, size, ((mp_limb_t) 1) << shift);
|
||
|
|
||
|
/* add back in saved bits from start of field */
|
||
|
arr[0] += save;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
}
|