1 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
   2 /*        All Rights Reserved   */
   3 
   4 
   5 /*
   6  * Copyright (c) 1980 Regents of the University of California.
   7  * All rights reserved.  The Berkeley software License Agreement
   8  * specifies the terms and conditions for redistribution.
   9  */
  10 /*      Portions Copyright(c) 1988, Sun Microsystems Inc.       */
  11 /*      All Rights Reserved                                     */
  12 
  13 /*
  14  * Copyright (c) 1997, by Sun Microsystems, Inc.
  15  * All rights reserved.
  16  */
  17 
  18 /*
  19  * Copyright (c) 2018, Joyent, Inc.
  20  */
  21 
  22 /* LINTLIBRARY */
  23 
  24 #include <mp.h>
  25 #include <stdio.h>
  26 #include <stdlib.h>
  27 #include <sys/types.h>
  28 #include "libmp.h"
  29 
  30 static void m_div(MINT *, MINT *, MINT *, MINT *);
  31 
  32 void
  33 mp_mdiv(MINT *a, MINT *b, MINT *q, MINT *r)
  34 {
  35         MINT x, y;
  36         int sign;
  37 
  38         sign = 1;
  39         x.len = y.len = 0;
  40         _mp_move(a, &x);
  41         _mp_move(b, &y);
  42         if (x.len < 0) {
  43                 sign = -1;
  44                 x.len = -x.len;
  45         }
  46         if (y.len < 0) {
  47                 sign = -sign;
  48                 y.len = -y.len;
  49         }
  50         _mp_xfree(q);
  51         _mp_xfree(r);
  52         m_div(&x, &y, q, r);
  53         if (sign == -1) {
  54                 q->len = -q->len;
  55                 r->len = -r->len;
  56         }
  57         _mp_xfree(&x);
  58         _mp_xfree(&y);
  59 }
  60 
  61 static int
  62 m_dsb(int qx, int n, short *a, short *b)
  63 {
  64         int borrow;
  65         int s3b2shit;
  66         int j;
  67         short fifteen = 15;
  68         short *aptr, *bptr;
  69 #ifdef DEBUGDSB
  70         (void) printf("m_dsb %d %d %d %d\n", qx, n, *a, *b);
  71 #endif
  72 
  73         borrow = 0;
  74         aptr = a;
  75         bptr = b;
  76         for (j = n; j > 0; j--) {
  77 #ifdef DEBUGDSB
  78                 (void) printf("1 borrow=%x %d %d %d\n", borrow, (*aptr * qx),
  79                     *bptr, *aptr);
  80 #endif
  81                 borrow -= (*aptr++) * qx - *bptr;
  82 #ifdef DEBUGDSB
  83                 (void) printf("2 borrow=%x %d %d %d\n", borrow, (*aptr * qx),
  84                     *bptr, *aptr);
  85 #endif
  86                 *bptr++ = (short)(borrow & 077777);
  87 #ifdef DEBUGDSB
  88                 (void) printf("3 borrow=%x %d %d %d\n", borrow, (*aptr * qx),
  89                     *bptr, *aptr);
  90 #endif
  91                 if (borrow >= 0) borrow >>= fifteen; /* 3b2 */
  92                 else borrow = 0xfffe0000 | (borrow >> fifteen);
  93 #ifdef DEBUGDSB
  94                 (void) printf("4 borrow=%x %d %d %d\n", borrow, (*aptr * qx),
  95                     *bptr, *aptr);
  96 #endif
  97         }
  98         borrow += *bptr;
  99         *bptr = (short)(borrow & 077777);
 100         if (borrow >= 0) s3b2shit = borrow >> fifteen; /* 3b2 */
 101         else s3b2shit = 0xfffe0000 | (borrow >> fifteen);
 102         if (s3b2shit == 0) {
 103 #ifdef DEBUGDSB
 104         (void) printf("mdsb 0\n");
 105 #endif
 106                 return (0);
 107         }
 108         borrow = 0;
 109         aptr = a;
 110         bptr = b;
 111         for (j = n; j > 0; j--) {
 112                 borrow += *aptr++ + *bptr;
 113                 *bptr++ = (short)(borrow & 077777);
 114                 if (borrow >= 0) borrow >>= fifteen; /* 3b2 */
 115                 else borrow = 0xfffe0000 | (borrow >>fifteen);
 116         }
 117 #ifdef DEBUGDSB
 118         (void) printf("mdsb 1\n");
 119 #endif
 120         return (1);
 121 }
 122 
 123 static int
 124 m_trq(short v1, short v2, short u1, short u2, short u3)
 125 {
 126         short d;
 127         int x1;
 128         int c1;
 129 
 130         c1 = u1 * 0100000 + u2;
 131         if (u1 == v1) {
 132                 d = 077777;
 133         } else {
 134                 d = (short)(c1 / v1);
 135         }
 136         do {
 137                 x1 = c1 - v1 * d;
 138                 x1 = x1 * 0100000 + u3 - v2 * d;
 139                 --d;
 140         } while (x1 < 0);
 141 #ifdef DEBUGMTRQ
 142         (void) printf("mtrq %d %d %d %d %d %d\n", v1, v2, u1, u2, u3, (d+1));
 143 #endif
 144         return ((int)d + 1);
 145 }
 146 
 147 static void
 148 m_div(MINT *a, MINT *b, MINT *q, MINT *r)
 149 {
 150         MINT u, v, x, w;
 151         short d;
 152         short *qval;
 153         short *uval;
 154         int j;
 155         int qq;
 156         int n;
 157         short v1;
 158         short v2;
 159 
 160         u.len = v.len = x.len = w.len = 0;
 161         if (b->len == 0) {
 162                 _mp_fatal("mdiv divide by zero");
 163                 return;
 164         }
 165         if (b->len == 1) {
 166                 r->val = _mp_xalloc(1, "m_div1");
 167                 mp_sdiv(a, b->val[0], q, r->val);
 168                 if (r->val[0] == 0) {
 169                         free(r->val);
 170                         r->len = 0;
 171                 } else {
 172                         r->len = 1;
 173                 }
 174                 return;
 175         }
 176         if (a -> len < b -> len) {
 177                 q->len = 0;
 178                 r->len = a->len;
 179                 r->val = _mp_xalloc(r->len, "m_div2");
 180                 for (qq = 0; qq < r->len; qq++) {
 181                         r->val[qq] = a->val[qq];
 182                 }
 183                 return;
 184         }
 185         x.len = 1;
 186         x.val = &d;
 187         n = b->len;
 188         d = 0100000 / (b->val[n - 1] + 1);
 189         mp_mult(a, &x, &u); /* subtle: relies on mult allocing extra space */
 190         mp_mult(b, &x, &v);
 191 #ifdef DEBUG_MDIV
 192         (void) printf("  u=%s\n", mtox(&u));
 193         (void) printf("  v=%s\n", mtox(&v));
 194 #endif
 195         v1 = v.val[n - 1];
 196         v2 = v.val[n - 2];
 197         qval = _mp_xalloc(a -> len - n + 1, "m_div3");
 198         uval = u.val;
 199         for (j = a->len - n; j >= 0; j--) {
 200                 qq = m_trq(v1, v2, uval[j + n], uval[j + n - 1],
 201                                                         uval[j + n - 2]);
 202                 if (m_dsb(qq, n, v.val, uval + j))
 203                         qq -= 1;
 204                 qval[j] = (short)qq;
 205         }
 206         x.len = n;
 207         x.val = u.val;
 208         _mp_mcan(&x);
 209 #ifdef DEBUG_MDIV
 210         (void) printf("  x=%s\n", mtox(&x));
 211         (void) printf("  d(in)=%d\n", (d));
 212 #endif
 213         mp_sdiv(&x, d, &w, &d);
 214 #ifdef DEBUG_MDIV
 215         (void) printf("  w=%s\n", mtox(&w));
 216         (void) printf("  d(out)=%d\n", (d));
 217 #endif
 218         r->len = w.len;
 219         r->val = w.val;
 220         q->val = qval;
 221         qq = a->len - n + 1;
 222         if (qq > 0 && qval[qq - 1] == 0)
 223                 qq -= 1;
 224         q->len = qq;
 225         if (qq == 0)
 226                 free(qval);
 227         if (x.len != 0)
 228                 _mp_xfree(&u);
 229         _mp_xfree(&v);
 230 }