1*86d7f5d3SJohn Marino /* mpz_cdiv_r_2exp, mpz_fdiv_r_2exp -- remainder from mpz divided by 2^n.
2*86d7f5d3SJohn Marino
3*86d7f5d3SJohn Marino Copyright 2001, 2002, 2004 Free Software Foundation, Inc.
4*86d7f5d3SJohn Marino
5*86d7f5d3SJohn Marino This file is part of the GNU MP Library.
6*86d7f5d3SJohn Marino
7*86d7f5d3SJohn Marino The GNU MP Library is free software; you can redistribute it and/or modify
8*86d7f5d3SJohn Marino it under the terms of the GNU Lesser General Public License as published by
9*86d7f5d3SJohn Marino the Free Software Foundation; either version 3 of the License, or (at your
10*86d7f5d3SJohn Marino option) any later version.
11*86d7f5d3SJohn Marino
12*86d7f5d3SJohn Marino The GNU MP Library is distributed in the hope that it will be useful, but
13*86d7f5d3SJohn Marino WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14*86d7f5d3SJohn Marino or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15*86d7f5d3SJohn Marino License for more details.
16*86d7f5d3SJohn Marino
17*86d7f5d3SJohn Marino You should have received a copy of the GNU Lesser General Public License
18*86d7f5d3SJohn Marino along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
19*86d7f5d3SJohn Marino
20*86d7f5d3SJohn Marino #include "gmp.h"
21*86d7f5d3SJohn Marino #include "gmp-impl.h"
22*86d7f5d3SJohn Marino
23*86d7f5d3SJohn Marino
24*86d7f5d3SJohn Marino /* Bit mask of "n" least significant bits of a limb. */
25*86d7f5d3SJohn Marino #define LOW_MASK(n) ((CNST_LIMB(1) << (n)) - 1)
26*86d7f5d3SJohn Marino
27*86d7f5d3SJohn Marino
28*86d7f5d3SJohn Marino /* dir==1 for ceil, dir==-1 for floor */
29*86d7f5d3SJohn Marino
30*86d7f5d3SJohn Marino static void __gmpz_cfdiv_r_2exp __GMP_PROTO ((REGPARM_3_1 (mpz_ptr, mpz_srcptr, mp_bitcnt_t, int))) REGPARM_ATTR (1);
31*86d7f5d3SJohn Marino #define cfdiv_r_2exp(w,u,cnt,dir) __gmpz_cfdiv_r_2exp (REGPARM_3_1 (w, u, cnt, dir))
32*86d7f5d3SJohn Marino
33*86d7f5d3SJohn Marino REGPARM_ATTR (1) static void
cfdiv_r_2exp(mpz_ptr w,mpz_srcptr u,mp_bitcnt_t cnt,int dir)34*86d7f5d3SJohn Marino cfdiv_r_2exp (mpz_ptr w, mpz_srcptr u, mp_bitcnt_t cnt, int dir)
35*86d7f5d3SJohn Marino {
36*86d7f5d3SJohn Marino mp_size_t usize, abs_usize, limb_cnt, i;
37*86d7f5d3SJohn Marino mp_srcptr up;
38*86d7f5d3SJohn Marino mp_ptr wp;
39*86d7f5d3SJohn Marino mp_limb_t high;
40*86d7f5d3SJohn Marino
41*86d7f5d3SJohn Marino usize = SIZ(u);
42*86d7f5d3SJohn Marino if (usize == 0)
43*86d7f5d3SJohn Marino {
44*86d7f5d3SJohn Marino SIZ(w) = 0;
45*86d7f5d3SJohn Marino return;
46*86d7f5d3SJohn Marino }
47*86d7f5d3SJohn Marino
48*86d7f5d3SJohn Marino limb_cnt = cnt / GMP_NUMB_BITS;
49*86d7f5d3SJohn Marino cnt %= GMP_NUMB_BITS;
50*86d7f5d3SJohn Marino abs_usize = ABS (usize);
51*86d7f5d3SJohn Marino
52*86d7f5d3SJohn Marino /* MPZ_REALLOC(w) below is only when w!=u, so we can fetch PTR(u) here
53*86d7f5d3SJohn Marino nice and early */
54*86d7f5d3SJohn Marino up = PTR(u);
55*86d7f5d3SJohn Marino
56*86d7f5d3SJohn Marino if ((usize ^ dir) < 0)
57*86d7f5d3SJohn Marino {
58*86d7f5d3SJohn Marino /* Round towards zero, means just truncate */
59*86d7f5d3SJohn Marino
60*86d7f5d3SJohn Marino if (w == u)
61*86d7f5d3SJohn Marino {
62*86d7f5d3SJohn Marino /* if already smaller than limb_cnt then do nothing */
63*86d7f5d3SJohn Marino if (abs_usize <= limb_cnt)
64*86d7f5d3SJohn Marino return;
65*86d7f5d3SJohn Marino wp = PTR(w);
66*86d7f5d3SJohn Marino }
67*86d7f5d3SJohn Marino else
68*86d7f5d3SJohn Marino {
69*86d7f5d3SJohn Marino i = MIN (abs_usize, limb_cnt+1);
70*86d7f5d3SJohn Marino MPZ_REALLOC (w, i);
71*86d7f5d3SJohn Marino wp = PTR(w);
72*86d7f5d3SJohn Marino MPN_COPY (wp, up, i);
73*86d7f5d3SJohn Marino
74*86d7f5d3SJohn Marino /* if smaller than limb_cnt then only the copy is needed */
75*86d7f5d3SJohn Marino if (abs_usize <= limb_cnt)
76*86d7f5d3SJohn Marino {
77*86d7f5d3SJohn Marino SIZ(w) = usize;
78*86d7f5d3SJohn Marino return;
79*86d7f5d3SJohn Marino }
80*86d7f5d3SJohn Marino }
81*86d7f5d3SJohn Marino }
82*86d7f5d3SJohn Marino else
83*86d7f5d3SJohn Marino {
84*86d7f5d3SJohn Marino /* Round away from zero, means twos complement if non-zero */
85*86d7f5d3SJohn Marino
86*86d7f5d3SJohn Marino /* if u!=0 and smaller than divisor, then must negate */
87*86d7f5d3SJohn Marino if (abs_usize <= limb_cnt)
88*86d7f5d3SJohn Marino goto negate;
89*86d7f5d3SJohn Marino
90*86d7f5d3SJohn Marino /* if non-zero low limb, then must negate */
91*86d7f5d3SJohn Marino for (i = 0; i < limb_cnt; i++)
92*86d7f5d3SJohn Marino if (up[i] != 0)
93*86d7f5d3SJohn Marino goto negate;
94*86d7f5d3SJohn Marino
95*86d7f5d3SJohn Marino /* if non-zero partial limb, then must negate */
96*86d7f5d3SJohn Marino if ((up[limb_cnt] & LOW_MASK (cnt)) != 0)
97*86d7f5d3SJohn Marino goto negate;
98*86d7f5d3SJohn Marino
99*86d7f5d3SJohn Marino /* otherwise low bits of u are zero, so that's the result */
100*86d7f5d3SJohn Marino SIZ(w) = 0;
101*86d7f5d3SJohn Marino return;
102*86d7f5d3SJohn Marino
103*86d7f5d3SJohn Marino negate:
104*86d7f5d3SJohn Marino /* twos complement negation to get 2**cnt-u */
105*86d7f5d3SJohn Marino
106*86d7f5d3SJohn Marino MPZ_REALLOC (w, limb_cnt+1);
107*86d7f5d3SJohn Marino up = PTR(u);
108*86d7f5d3SJohn Marino wp = PTR(w);
109*86d7f5d3SJohn Marino
110*86d7f5d3SJohn Marino /* Ones complement */
111*86d7f5d3SJohn Marino i = MIN (abs_usize, limb_cnt+1);
112*86d7f5d3SJohn Marino mpn_com (wp, up, i);
113*86d7f5d3SJohn Marino for ( ; i <= limb_cnt; i++)
114*86d7f5d3SJohn Marino wp[i] = GMP_NUMB_MAX;
115*86d7f5d3SJohn Marino
116*86d7f5d3SJohn Marino /* Twos complement. Since u!=0 in the relevant part, the twos
117*86d7f5d3SJohn Marino complement never gives 0 and a carry, so can use MPN_INCR_U. */
118*86d7f5d3SJohn Marino MPN_INCR_U (wp, limb_cnt+1, CNST_LIMB(1));
119*86d7f5d3SJohn Marino
120*86d7f5d3SJohn Marino usize = -usize;
121*86d7f5d3SJohn Marino }
122*86d7f5d3SJohn Marino
123*86d7f5d3SJohn Marino /* Mask the high limb */
124*86d7f5d3SJohn Marino high = wp[limb_cnt];
125*86d7f5d3SJohn Marino high &= LOW_MASK (cnt);
126*86d7f5d3SJohn Marino wp[limb_cnt] = high;
127*86d7f5d3SJohn Marino
128*86d7f5d3SJohn Marino /* Strip any consequent high zeros */
129*86d7f5d3SJohn Marino while (high == 0)
130*86d7f5d3SJohn Marino {
131*86d7f5d3SJohn Marino limb_cnt--;
132*86d7f5d3SJohn Marino if (limb_cnt < 0)
133*86d7f5d3SJohn Marino {
134*86d7f5d3SJohn Marino SIZ(w) = 0;
135*86d7f5d3SJohn Marino return;
136*86d7f5d3SJohn Marino }
137*86d7f5d3SJohn Marino high = wp[limb_cnt];
138*86d7f5d3SJohn Marino }
139*86d7f5d3SJohn Marino
140*86d7f5d3SJohn Marino limb_cnt++;
141*86d7f5d3SJohn Marino SIZ(w) = (usize >= 0 ? limb_cnt : -limb_cnt);
142*86d7f5d3SJohn Marino }
143*86d7f5d3SJohn Marino
144*86d7f5d3SJohn Marino
145*86d7f5d3SJohn Marino void
mpz_cdiv_r_2exp(mpz_ptr w,mpz_srcptr u,mp_bitcnt_t cnt)146*86d7f5d3SJohn Marino mpz_cdiv_r_2exp (mpz_ptr w, mpz_srcptr u, mp_bitcnt_t cnt)
147*86d7f5d3SJohn Marino {
148*86d7f5d3SJohn Marino cfdiv_r_2exp (w, u, cnt, 1);
149*86d7f5d3SJohn Marino }
150*86d7f5d3SJohn Marino
151*86d7f5d3SJohn Marino void
mpz_fdiv_r_2exp(mpz_ptr w,mpz_srcptr u,mp_bitcnt_t cnt)152*86d7f5d3SJohn Marino mpz_fdiv_r_2exp (mpz_ptr w, mpz_srcptr u, mp_bitcnt_t cnt)
153*86d7f5d3SJohn Marino {
154*86d7f5d3SJohn Marino cfdiv_r_2exp (w, u, cnt, -1);
155*86d7f5d3SJohn Marino }
156