xref: /csrg-svn/lib/libc/quad/qdivrem.c (revision 53430)
1*53430Sbostic /*-
2*53430Sbostic  * Copyright (c) 1992 The Regents of the University of California.
3*53430Sbostic  * All rights reserved.
4*53430Sbostic  *
5*53430Sbostic  * %sccs.include.redist.c%
6*53430Sbostic  */
7*53430Sbostic 
8*53430Sbostic #if defined(LIBC_SCCS) && !defined(lint)
9*53430Sbostic static char sccsid[] = "@(#)qdivrem.c	5.3 (Berkeley) 05/12/92";
10*53430Sbostic #endif /* LIBC_SCCS and not lint */
11*53430Sbostic 
1251748Smckusick #include "longlong.h"
1351748Smckusick 
1451748Smckusick static int bshift ();
1551748Smckusick 
1651748Smckusick /* Divide a by b, producing quotient q and remainder r.
1751748Smckusick 
1851748Smckusick        sizeof a is m
1951748Smckusick        sizeof b is n
2051748Smckusick        sizeof q is m - n
2151748Smckusick        sizeof r is n
2251748Smckusick 
2351748Smckusick    The quotient must fit in m - n bytes, i.e., the most significant
2451748Smckusick    n digits of a must be less than b, and m must be greater than n.  */
2551748Smckusick 
2651748Smckusick /* The name of this used to be __div_internal,
2751748Smckusick    but that is too long for SYSV.  */
2851748Smckusick 
2951748Smckusick void
3051748Smckusick __bdiv (a, b, q, r, m, n)
3151748Smckusick      unsigned short *a, *b, *q, *r;
3251748Smckusick      size_t m, n;
3351748Smckusick {
3451748Smckusick   unsigned long qhat, rhat;
3551748Smckusick   unsigned long acc;
3651748Smckusick   unsigned short *u = (unsigned short *) alloca (m);
3751748Smckusick   unsigned short *v = (unsigned short *) alloca (n);
3851748Smckusick   unsigned short *u0, *u1, *u2;
3951748Smckusick   unsigned short *v0;
4051748Smckusick   int d, qn;
4151748Smckusick   int i, j;
4251748Smckusick 
4351748Smckusick   m /= sizeof *a;
4451748Smckusick   n /= sizeof *b;
4551748Smckusick   qn = m - n;
4651748Smckusick 
4751748Smckusick   /* Remove leading zero digits from divisor, and the same number of
4851748Smckusick      digits (which must be zero) from dividend.  */
4951748Smckusick 
5051748Smckusick   while (b[big_end (n)] == 0)
5151748Smckusick     {
5251748Smckusick       r[big_end (n)] = 0;
5351748Smckusick 
5451748Smckusick       a += little_end (2);
5551748Smckusick       b += little_end (2);
5651748Smckusick       r += little_end (2);
5751748Smckusick       m--;
5851748Smckusick       n--;
5951748Smckusick 
6051748Smckusick       /* Check for zero divisor.  */
6151748Smckusick       if (n == 0)
6251750Smckusick       {
6351750Smckusick 	*r /= n;	/* force a divide-by-zero trap */
6451750Smckusick 	return;
6551750Smckusick       }
6651748Smckusick     }
6751748Smckusick 
6851748Smckusick   /* If divisor is a single digit, do short division.  */
6951748Smckusick 
7051748Smckusick   if (n == 1)
7151748Smckusick     {
7251748Smckusick       acc = a[big_end (m)];
7351748Smckusick       a += little_end (2);
7451748Smckusick       for (j = big_end (qn); is_not_lsd (j, qn); j = next_lsd (j))
7551748Smckusick 	{
7651748Smckusick 	  acc = (acc << 16) | a[j];
7751748Smckusick 	  q[j] = acc / *b;
7851748Smckusick 	  acc = acc % *b;
7951748Smckusick 	}
8051748Smckusick       *r = acc;
8151748Smckusick       return;
8251748Smckusick     }
8351748Smckusick 
8451748Smckusick   /* No such luck, must do long division. Shift divisor and dividend
8551748Smckusick      left until the high bit of the divisor is 1.  */
8651748Smckusick 
8751748Smckusick   for (d = 0; d < 16; d++)
8851748Smckusick     if (b[big_end (n)] & (1 << (16 - 1 - d)))
8951748Smckusick       break;
9051748Smckusick 
9151748Smckusick   bshift (a, d, u, 0, m);
9251748Smckusick   bshift (b, d, v, 0, n);
9351748Smckusick 
9451748Smckusick   /* Get pointers to the high dividend and divisor digits.  */
9551748Smckusick 
9651748Smckusick   u0 = u + big_end (m) - big_end (qn);
9751748Smckusick   u1 = next_lsd (u0);
9851748Smckusick   u2 = next_lsd (u1);
9951748Smckusick   u += little_end (2);
10051748Smckusick 
10151748Smckusick   v0 = v + big_end (n);
10251748Smckusick 
10351748Smckusick   /* Main loop: find a quotient digit, multiply it by the divisor,
10451748Smckusick      and subtract that from the dividend, shifted over the right amount. */
10551748Smckusick 
10651748Smckusick   for (j = big_end (qn); is_not_lsd (j, qn); j = next_lsd (j))
10751748Smckusick     {
10851748Smckusick       /* Quotient digit initial guess: high 2 dividend digits over high
10951748Smckusick 	 divisor digit.  */
11051748Smckusick 
11151748Smckusick       if (u0[j] == *v0)
11251748Smckusick 	{
11351748Smckusick 	  qhat = B - 1;
11451748Smckusick 	  rhat = (unsigned long) *v0 + u1[j];
11551748Smckusick 	}
11651748Smckusick       else
11751748Smckusick 	{
11851748Smckusick 	  unsigned long numerator = ((unsigned long) u0[j] << 16) | u1[j];
11951748Smckusick 	  qhat = numerator / *v0;
12051748Smckusick 	  rhat = numerator % *v0;
12151748Smckusick 	}
12251748Smckusick 
12351748Smckusick       /* Now get the quotient right for high 3 dividend digits over
12451748Smckusick 	 high 2 divisor digits.  */
12551748Smckusick 
12651748Smckusick       while (rhat < B && qhat * *next_lsd (v0) > ((rhat << 16) | u2[j]))
12751748Smckusick 	{
12851748Smckusick 	  qhat -= 1;
12951748Smckusick 	  rhat += *v0;
13051748Smckusick 	}
13151748Smckusick 
13251748Smckusick       /* Multiply quotient by divisor, subtract from dividend.  */
13351748Smckusick 
13451748Smckusick       acc = 0;
13551748Smckusick       for (i = little_end (n); is_not_msd (i, n); i = next_msd (i))
13651748Smckusick 	{
13751748Smckusick 	  acc += (unsigned long) (u + j)[i] - v[i] * qhat;
13851748Smckusick 	  (u + j)[i] = acc & low16;
13951748Smckusick 	  if (acc < B)
14051748Smckusick 	    acc = 0;
14151748Smckusick 	  else
14251748Smckusick 	    acc = (acc >> 16) | -B;
14351748Smckusick 	}
14451748Smckusick 
14551748Smckusick       q[j] = qhat;
14651748Smckusick 
14751748Smckusick       /* Quotient may have been too high by 1.  If dividend went negative,
14851748Smckusick 	 decrement the quotient by 1 and add the divisor back.  */
14951748Smckusick 
15051748Smckusick       if ((signed long) (acc + u0[j]) < 0)
15151748Smckusick 	{
15251748Smckusick 	  q[j] -= 1;
15351748Smckusick 	  acc = 0;
15451748Smckusick 	  for (i = little_end (n); is_not_msd (i, n); i = next_msd (i))
15551748Smckusick 	    {
15651748Smckusick 	      acc += (unsigned long) (u + j)[i] + v[i];
15751748Smckusick 	      (u + j)[i] = acc & low16;
15851748Smckusick 	      acc = acc >> 16;
15951748Smckusick 	    }
16051748Smckusick 	}
16151748Smckusick     }
16251748Smckusick 
16351748Smckusick   /* Now the remainder is what's left of the dividend, shifted right
16451748Smckusick      by the amount of the normalizing left shift at the top.  */
16551748Smckusick 
16651748Smckusick   r[big_end (n)] = bshift (u + 1 + little_end (j - 1),
16751748Smckusick 			   16 - d,
16851748Smckusick 			   r + little_end (2),
16951748Smckusick 			   u[little_end (m - 1)] >> d,
17051748Smckusick 			   n - 1);
17151748Smckusick }
17251748Smckusick 
17351748Smckusick /* Left shift U by K giving W; fill the introduced low-order bits with
17451748Smckusick    CARRY_IN.  Length of U and W is N.  Return carry out.  K must be
17551748Smckusick    in 0 .. 16.  */
17651748Smckusick 
17751748Smckusick static int
17851748Smckusick bshift (u, k, w, carry_in, n)
17951748Smckusick      unsigned short *u, *w, carry_in;
18051748Smckusick      int k, n;
18151748Smckusick {
18251748Smckusick   unsigned long acc;
18351748Smckusick   int i;
18451748Smckusick 
18551748Smckusick   if (k == 0)
18651748Smckusick     {
18751750Smckusick       while (n-- > 0)
18851750Smckusick         *w++ = *u++;
18951748Smckusick       return 0;
19051748Smckusick     }
19151748Smckusick 
19251748Smckusick   acc = carry_in;
19351748Smckusick   for (i = little_end (n); is_not_msd (i, n); i = next_msd (i))
19451748Smckusick     {
19551748Smckusick       acc |= (unsigned long) u[i] << k;
19651748Smckusick       w[i] = acc & low16;
19751748Smckusick       acc = acc >> 16;
19851748Smckusick     }
19951748Smckusick   return acc;
20051748Smckusick }
201