buildtools/gcc/gmp/mpz/cfdiv_r_2exp.c
Jérôme Duval b58ddff026 * modified gcc Makefile.in to copy gmp-impl.h and longlong.h headers to build gmp directory (see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44455 ).
* merged mpfr 3.0.0 and gmp 5.0.1 in buildtools trunk


git-svn-id: file:///srv/svn/repos/haiku/buildtools/trunk@37378 a95241bf-73f2-0310-859d-f6bbb57e9c96
2010-07-03 15:21:01 +00:00

156 lines
3.9 KiB
C

/* mpz_cdiv_r_2exp, mpz_fdiv_r_2exp -- remainder from mpz divided by 2^n.
Copyright 2001, 2002, 2004 Free Software Foundation, Inc.
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 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.
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 Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
#include "gmp.h"
#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 __GMP_PROTO ((REGPARM_3_1 (mpz_ptr, mpz_srcptr, mp_bitcnt_t, int))) REGPARM_ATTR (1);
#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 = PTR(w);
}
else
{
i = MIN (abs_usize, limb_cnt+1);
MPZ_REALLOC (w, i);
wp = PTR(w);
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;
}
}
}
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;
/* if non-zero low limb, then must negate */
for (i = 0; i < limb_cnt; i++)
if (up[i] != 0)
goto negate;
/* if non-zero partial limb, then must negate */
if ((up[limb_cnt] & LOW_MASK (cnt)) != 0)
goto negate;
/* 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 */
MPZ_REALLOC (w, limb_cnt+1);
up = PTR(u);
wp = PTR(w);
/* Ones complement */
i = MIN (abs_usize, limb_cnt+1);
mpn_com (wp, up, i);
for ( ; i <= limb_cnt; i++)
wp[i] = GMP_NUMB_MAX;
/* Twos complement. Since u!=0 in the relevant part, the twos
complement never gives 0 and a carry, so can use MPN_INCR_U. */
MPN_INCR_U (wp, limb_cnt+1, CNST_LIMB(1));
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;
}
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);
}