buildtools/gcc/gmp/mpz/cfdiv_r_2exp.c

160 lines
3.7 KiB
C
Raw Permalink Normal View History

2018-03-19 15:46:45 -05:00
/* mpz_cdiv_r_2exp, mpz_fdiv_r_2exp -- remainder from mpz divided by 2^n.
Copyright 2001, 2002, 2004, 2012 Free Software Foundation, Inc.
2018-03-19 15:46:45 -05:00
This file is part of the GNU MP Library.
The GNU MP Library is free software; you can redistribute it and/or modify
it under the terms of either:
* the GNU Lesser General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your
option) any later version.
or
* 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.
or both in parallel, as here.
2018-03-19 15:46:45 -05:00
The GNU MP Library 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.
2018-03-19 15:46:45 -05:00
You should have received copies of the GNU General Public License and the
GNU Lesser General Public License along with the GNU MP Library. If not,
see https://www.gnu.org/licenses/. */
2018-03-19 15:46:45 -05:00
#include "gmp-impl.h"
/* Bit mask of "n" least significant bits of a limb. */
#define LOW_MASK(n) ((CNST_LIMB(1) << (n)) - 1)
/* dir==1 for ceil, dir==-1 for floor */
static void __gmpz_cfdiv_r_2exp (REGPARM_3_1 (mpz_ptr, mpz_srcptr, mp_bitcnt_t, int)) REGPARM_ATTR (1);
2018-03-19 15:46:45 -05:00
#define cfdiv_r_2exp(w,u,cnt,dir) __gmpz_cfdiv_r_2exp (REGPARM_3_1 (w, u, cnt, dir))
REGPARM_ATTR (1) static void
cfdiv_r_2exp (mpz_ptr w, mpz_srcptr u, mp_bitcnt_t cnt, int dir)
{
mp_size_t usize, abs_usize, limb_cnt, i;
mp_srcptr up;
mp_ptr wp;
mp_limb_t high;
usize = SIZ(u);
if (usize == 0)
{
SIZ(w) = 0;
return;
}
limb_cnt = cnt / GMP_NUMB_BITS;
cnt %= GMP_NUMB_BITS;
abs_usize = ABS (usize);
/* MPZ_REALLOC(w) below is only when w!=u, so we can fetch PTR(u) here
nice and early */
up = PTR(u);
if ((usize ^ dir) < 0)
{
/* Round towards zero, means just truncate */
if (w == u)
{
/* if already smaller than limb_cnt then do nothing */
if (abs_usize <= limb_cnt)
return;
wp = (mp_ptr) up;
}
2018-03-19 15:46:45 -05:00
else
{
i = MIN (abs_usize, limb_cnt+1);
wp = MPZ_NEWALLOC (w, i);
MPN_COPY (wp, up, i);
/* if smaller than limb_cnt then only the copy is needed */
if (abs_usize <= limb_cnt)
{
SIZ(w) = usize;
return;
}
}
2018-03-19 15:46:45 -05:00
}
else
{
/* Round away from zero, means twos complement if non-zero */
/* if u!=0 and smaller than divisor, then must negate */
if (abs_usize <= limb_cnt)
goto negate;
2018-03-19 15:46:45 -05:00
/* if non-zero low limb, then must negate */
for (i = 0; i < limb_cnt; i++)
if (up[i] != 0)
goto negate;
2018-03-19 15:46:45 -05:00
/* if non-zero partial limb, then must negate */
if ((up[limb_cnt] & LOW_MASK (cnt)) != 0)
goto negate;
2018-03-19 15:46:45 -05:00
/* otherwise low bits of u are zero, so that's the result */
SIZ(w) = 0;
return;
negate:
/* twos complement negation to get 2**cnt-u */
wp = MPZ_REALLOC (w, limb_cnt+1);
2018-03-19 15:46:45 -05:00
up = PTR(u);
/* Ones complement */
i = MIN (abs_usize, limb_cnt+1);
ASSERT_CARRY (mpn_neg (wp, up, i));
2018-03-19 15:46:45 -05:00
for ( ; i <= limb_cnt; i++)
wp[i] = GMP_NUMB_MAX;
2018-03-19 15:46:45 -05:00
usize = -usize;
}
/* Mask the high limb */
high = wp[limb_cnt];
high &= LOW_MASK (cnt);
wp[limb_cnt] = high;
/* Strip any consequent high zeros */
while (high == 0)
{
limb_cnt--;
if (limb_cnt < 0)
{
SIZ(w) = 0;
return;
}
2018-03-19 15:46:45 -05:00
high = wp[limb_cnt];
}
limb_cnt++;
SIZ(w) = (usize >= 0 ? limb_cnt : -limb_cnt);
}
void
mpz_cdiv_r_2exp (mpz_ptr w, mpz_srcptr u, mp_bitcnt_t cnt)
{
cfdiv_r_2exp (w, u, cnt, 1);
}
void
mpz_fdiv_r_2exp (mpz_ptr w, mpz_srcptr u, mp_bitcnt_t cnt)
{
cfdiv_r_2exp (w, u, cnt, -1);
}