xref: /dflybsd-src/contrib/gmp/mpz/cfdiv_r_2exp.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
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