xref: /csrg-svn/lib/libc/quad/qdivrem.c (revision 51748)
1*51748Smckusick #include "longlong.h"
2*51748Smckusick 
3*51748Smckusick static int bshift ();
4*51748Smckusick 
5*51748Smckusick /* Divide a by b, producing quotient q and remainder r.
6*51748Smckusick 
7*51748Smckusick        sizeof a is m
8*51748Smckusick        sizeof b is n
9*51748Smckusick        sizeof q is m - n
10*51748Smckusick        sizeof r is n
11*51748Smckusick 
12*51748Smckusick    The quotient must fit in m - n bytes, i.e., the most significant
13*51748Smckusick    n digits of a must be less than b, and m must be greater than n.  */
14*51748Smckusick 
15*51748Smckusick /* The name of this used to be __div_internal,
16*51748Smckusick    but that is too long for SYSV.  */
17*51748Smckusick 
18*51748Smckusick void
19*51748Smckusick __bdiv (a, b, q, r, m, n)
20*51748Smckusick      unsigned short *a, *b, *q, *r;
21*51748Smckusick      size_t m, n;
22*51748Smckusick {
23*51748Smckusick   unsigned long qhat, rhat;
24*51748Smckusick   unsigned long acc;
25*51748Smckusick   unsigned short *u = (unsigned short *) alloca (m);
26*51748Smckusick   unsigned short *v = (unsigned short *) alloca (n);
27*51748Smckusick   unsigned short *u0, *u1, *u2;
28*51748Smckusick   unsigned short *v0;
29*51748Smckusick   int d, qn;
30*51748Smckusick   int i, j;
31*51748Smckusick 
32*51748Smckusick   m /= sizeof *a;
33*51748Smckusick   n /= sizeof *b;
34*51748Smckusick   qn = m - n;
35*51748Smckusick 
36*51748Smckusick   /* Remove leading zero digits from divisor, and the same number of
37*51748Smckusick      digits (which must be zero) from dividend.  */
38*51748Smckusick 
39*51748Smckusick   while (b[big_end (n)] == 0)
40*51748Smckusick     {
41*51748Smckusick       r[big_end (n)] = 0;
42*51748Smckusick 
43*51748Smckusick       a += little_end (2);
44*51748Smckusick       b += little_end (2);
45*51748Smckusick       r += little_end (2);
46*51748Smckusick       m--;
47*51748Smckusick       n--;
48*51748Smckusick 
49*51748Smckusick       /* Check for zero divisor.  */
50*51748Smckusick       if (n == 0)
51*51748Smckusick 	abort ();
52*51748Smckusick     }
53*51748Smckusick 
54*51748Smckusick   /* If divisor is a single digit, do short division.  */
55*51748Smckusick 
56*51748Smckusick   if (n == 1)
57*51748Smckusick     {
58*51748Smckusick       acc = a[big_end (m)];
59*51748Smckusick       a += little_end (2);
60*51748Smckusick       for (j = big_end (qn); is_not_lsd (j, qn); j = next_lsd (j))
61*51748Smckusick 	{
62*51748Smckusick 	  acc = (acc << 16) | a[j];
63*51748Smckusick 	  q[j] = acc / *b;
64*51748Smckusick 	  acc = acc % *b;
65*51748Smckusick 	}
66*51748Smckusick       *r = acc;
67*51748Smckusick       return;
68*51748Smckusick     }
69*51748Smckusick 
70*51748Smckusick   /* No such luck, must do long division. Shift divisor and dividend
71*51748Smckusick      left until the high bit of the divisor is 1.  */
72*51748Smckusick 
73*51748Smckusick   for (d = 0; d < 16; d++)
74*51748Smckusick     if (b[big_end (n)] & (1 << (16 - 1 - d)))
75*51748Smckusick       break;
76*51748Smckusick 
77*51748Smckusick   bshift (a, d, u, 0, m);
78*51748Smckusick   bshift (b, d, v, 0, n);
79*51748Smckusick 
80*51748Smckusick   /* Get pointers to the high dividend and divisor digits.  */
81*51748Smckusick 
82*51748Smckusick   u0 = u + big_end (m) - big_end (qn);
83*51748Smckusick   u1 = next_lsd (u0);
84*51748Smckusick   u2 = next_lsd (u1);
85*51748Smckusick   u += little_end (2);
86*51748Smckusick 
87*51748Smckusick   v0 = v + big_end (n);
88*51748Smckusick 
89*51748Smckusick   /* Main loop: find a quotient digit, multiply it by the divisor,
90*51748Smckusick      and subtract that from the dividend, shifted over the right amount. */
91*51748Smckusick 
92*51748Smckusick   for (j = big_end (qn); is_not_lsd (j, qn); j = next_lsd (j))
93*51748Smckusick     {
94*51748Smckusick       /* Quotient digit initial guess: high 2 dividend digits over high
95*51748Smckusick 	 divisor digit.  */
96*51748Smckusick 
97*51748Smckusick       if (u0[j] == *v0)
98*51748Smckusick 	{
99*51748Smckusick 	  qhat = B - 1;
100*51748Smckusick 	  rhat = (unsigned long) *v0 + u1[j];
101*51748Smckusick 	}
102*51748Smckusick       else
103*51748Smckusick 	{
104*51748Smckusick 	  unsigned long numerator = ((unsigned long) u0[j] << 16) | u1[j];
105*51748Smckusick 	  qhat = numerator / *v0;
106*51748Smckusick 	  rhat = numerator % *v0;
107*51748Smckusick 	}
108*51748Smckusick 
109*51748Smckusick       /* Now get the quotient right for high 3 dividend digits over
110*51748Smckusick 	 high 2 divisor digits.  */
111*51748Smckusick 
112*51748Smckusick       while (rhat < B && qhat * *next_lsd (v0) > ((rhat << 16) | u2[j]))
113*51748Smckusick 	{
114*51748Smckusick 	  qhat -= 1;
115*51748Smckusick 	  rhat += *v0;
116*51748Smckusick 	}
117*51748Smckusick 
118*51748Smckusick       /* Multiply quotient by divisor, subtract from dividend.  */
119*51748Smckusick 
120*51748Smckusick       acc = 0;
121*51748Smckusick       for (i = little_end (n); is_not_msd (i, n); i = next_msd (i))
122*51748Smckusick 	{
123*51748Smckusick 	  acc += (unsigned long) (u + j)[i] - v[i] * qhat;
124*51748Smckusick 	  (u + j)[i] = acc & low16;
125*51748Smckusick 	  if (acc < B)
126*51748Smckusick 	    acc = 0;
127*51748Smckusick 	  else
128*51748Smckusick 	    acc = (acc >> 16) | -B;
129*51748Smckusick 	}
130*51748Smckusick 
131*51748Smckusick       q[j] = qhat;
132*51748Smckusick 
133*51748Smckusick       /* Quotient may have been too high by 1.  If dividend went negative,
134*51748Smckusick 	 decrement the quotient by 1 and add the divisor back.  */
135*51748Smckusick 
136*51748Smckusick       if ((signed long) (acc + u0[j]) < 0)
137*51748Smckusick 	{
138*51748Smckusick 	  q[j] -= 1;
139*51748Smckusick 	  acc = 0;
140*51748Smckusick 	  for (i = little_end (n); is_not_msd (i, n); i = next_msd (i))
141*51748Smckusick 	    {
142*51748Smckusick 	      acc += (unsigned long) (u + j)[i] + v[i];
143*51748Smckusick 	      (u + j)[i] = acc & low16;
144*51748Smckusick 	      acc = acc >> 16;
145*51748Smckusick 	    }
146*51748Smckusick 	}
147*51748Smckusick     }
148*51748Smckusick 
149*51748Smckusick   /* Now the remainder is what's left of the dividend, shifted right
150*51748Smckusick      by the amount of the normalizing left shift at the top.  */
151*51748Smckusick 
152*51748Smckusick   r[big_end (n)] = bshift (u + 1 + little_end (j - 1),
153*51748Smckusick 			   16 - d,
154*51748Smckusick 			   r + little_end (2),
155*51748Smckusick 			   u[little_end (m - 1)] >> d,
156*51748Smckusick 			   n - 1);
157*51748Smckusick }
158*51748Smckusick 
159*51748Smckusick /* Left shift U by K giving W; fill the introduced low-order bits with
160*51748Smckusick    CARRY_IN.  Length of U and W is N.  Return carry out.  K must be
161*51748Smckusick    in 0 .. 16.  */
162*51748Smckusick 
163*51748Smckusick static int
164*51748Smckusick bshift (u, k, w, carry_in, n)
165*51748Smckusick      unsigned short *u, *w, carry_in;
166*51748Smckusick      int k, n;
167*51748Smckusick {
168*51748Smckusick   unsigned long acc;
169*51748Smckusick   int i;
170*51748Smckusick 
171*51748Smckusick   if (k == 0)
172*51748Smckusick     {
173*51748Smckusick       bcopy (u, w, n * sizeof *u);
174*51748Smckusick       return 0;
175*51748Smckusick     }
176*51748Smckusick 
177*51748Smckusick   acc = carry_in;
178*51748Smckusick   for (i = little_end (n); is_not_msd (i, n); i = next_msd (i))
179*51748Smckusick     {
180*51748Smckusick       acc |= (unsigned long) u[i] << k;
181*51748Smckusick       w[i] = acc & low16;
182*51748Smckusick       acc = acc >> 16;
183*51748Smckusick     }
184*51748Smckusick   return acc;
185*51748Smckusick }
186