experiment 1 with
[libreriscv.git] / openpower / sv / bitmanip / divmnu64.c
1 /* original source code from Hackers-Delight
2 https://github.com/hcs0/Hackers-Delight
3 */
4 /* This divides an n-word dividend by an m-word divisor, giving an
5 n-m+1-word quotient and m-word remainder. The bignums are in arrays of
6 words. Here a "word" is 32 bits. This routine is designed for a 64-bit
7 machine which has a 64/64 division instruction. */
8
9 #include <stdio.h>
10 #include <stdlib.h> //To define "exit", req'd by XLC.
11
12 #define max(x, y) ((x) > (y) ? (x) : (y))
13
14 int nlz(unsigned x) {
15 int n;
16
17 if (x == 0) return(32);
18 n = 0;
19 if (x <= 0x0000FFFF) {n = n +16; x = x <<16;}
20 if (x <= 0x00FFFFFF) {n = n + 8; x = x << 8;}
21 if (x <= 0x0FFFFFFF) {n = n + 4; x = x << 4;}
22 if (x <= 0x3FFFFFFF) {n = n + 2; x = x << 2;}
23 if (x <= 0x7FFFFFFF) {n = n + 1;}
24 return n;
25 }
26
27 void dumpit(char *msg, int n, unsigned v[]) {
28 int i;
29 printf(msg);
30 for (i = n-1; i >= 0; i--) printf(" %08x", v[i]);
31 printf("\n");
32 }
33
34 /* q[0], r[0], u[0], and v[0] contain the LEAST significant words.
35 (The sequence is in little-endian order).
36
37 This is a fairly precise implementation of Knuth's Algorithm D, for a
38 binary computer with base b = 2**32. The caller supplies:
39 1. Space q for the quotient, m - n + 1 words (at least one).
40 2. Space r for the remainder (optional), n words.
41 3. The dividend u, m words, m >= 1.
42 4. The divisor v, n words, n >= 2.
43 The most significant digit of the divisor, v[n-1], must be nonzero. The
44 dividend u may have leading zeros; this just makes the algorithm take
45 longer and makes the quotient contain more leading zeros. A value of
46 NULL may be given for the address of the remainder to signify that the
47 caller does not want the remainder.
48 The program does not alter the input parameters u and v.
49 The quotient and remainder returned may have leading zeros. The
50 function itself returns a value of 0 for success and 1 for invalid
51 parameters (e.g., division by 0).
52 For now, we must have m >= n. Knuth's Algorithm D also requires
53 that the dividend be at least as long as the divisor. (In his terms,
54 m >= 0 (unstated). Therefore m+n >= n.) */
55
56 int divmnu(unsigned q[], unsigned r[],
57 const unsigned u[], const unsigned v[],
58 int m, int n) {
59
60 const unsigned long long b = 4294967296LL; // Number base (2**32).
61 unsigned *un, *vn; // Normalized form of u, v.
62 unsigned long long qhat; // Estimated quotient digit.
63 unsigned long long rhat; // A remainder.
64 unsigned long long p; // Product of two digits.
65 long long t, k;
66 int s, i, j;
67
68 if (m < n || n <= 0 || v[n-1] == 0)
69 return 1; // Return if invalid param.
70
71 if (n == 1) { // Take care of
72 k = 0; // the case of a
73 for (j = m - 1; j >= 0; j--) { // single-digit
74 q[j] = (k*b + u[j])/v[0]; // divisor here.
75 k = (k*b + u[j]) - q[j]*v[0];
76 }
77 if (r != NULL) r[0] = k;
78 return 0;
79 }
80
81 /* Normalize by shifting v left just enough so that its high-order
82 bit is on, and shift u left the same amount. We may have to append a
83 high-order digit on the dividend; we do that unconditionally. */
84
85 s = nlz(v[n-1]); // 0 <= s <= 31.
86 vn = (unsigned *)alloca(4*n);
87 for (i = n - 1; i > 0; i--)
88 vn[i] = (v[i] << s) | ((unsigned long long)v[i-1] >> (32-s));
89 vn[0] = v[0] << s;
90
91 un = (unsigned *)alloca(4*(m + 1));
92 un[m] = (unsigned long long)u[m-1] >> (32-s);
93 for (i = m - 1; i > 0; i--)
94 un[i] = (u[i] << s) | ((unsigned long long)u[i-1] >> (32-s));
95 un[0] = u[0] << s;
96
97 for (j = m - n; j >= 0; j--) { // Main loop.
98 // Compute estimate qhat of q[j].
99 qhat = (un[j+n]*b + un[j+n-1])/vn[n-1];
100 rhat = (un[j+n]*b + un[j+n-1]) - qhat*vn[n-1];
101 again:
102 if (qhat >= b || qhat*vn[n-2] > b*rhat + un[j+n-2])
103 { qhat = qhat - 1;
104 rhat = rhat + vn[n-1];
105 if (rhat < b) goto again;
106 }
107
108 // Multiply and subtract.
109 k = 0;
110 #ifdef ORIGINAL
111 for (i = 0; i < n; i++) {
112 p = qhat*vn[i];
113 t = un[i+j] - k - (p & 0xFFFFFFFFLL);
114 un[i+j] = t;
115 k = (p >> 32) - (t >> 32);
116 }
117 #else
118 for (i = 0; i < n; i++) {
119 unsigned rhi;
120 unsigned long long sum;
121 p = ((unsigned long long)un[i+j])+ ~(qhat*vn[i]) + k;
122 rhi = (p >> 32);
123 if (((unsigned long long)k) <= 1) rhi += 1;
124 k = rhi;
125 un[i+j] = sum & 0xffffffff;
126 }
127 #endif
128 t = un[j+n] - k;
129 un[j+n] = t;
130
131 q[j] = qhat; // Store quotient digit.
132 if (t < 0) { // If we subtracted too
133 q[j] = q[j] - 1; // much, add back.
134 k = 0;
135 for (i = 0; i < n; i++) {
136 t = (unsigned long long)un[i+j] + vn[i] + k;
137 un[i+j] = t;
138 k = t >> 32;
139 }
140 un[j+n] = un[j+n] + k;
141 }
142 } // End j.
143 // If the caller wants the remainder, unnormalize
144 // it and pass it back.
145 if (r != NULL) {
146 for (i = 0; i < n-1; i++)
147 r[i] = (un[i] >> s) | ((unsigned long long)un[i+1] << (32-s));
148 r[n-1] = un[n-1] >> s;
149 }
150 return 0;
151 }
152
153 int errors;
154
155 void check(unsigned q[], unsigned r[],
156 unsigned u[], unsigned v[],
157 int m, int n,
158 unsigned cq[], unsigned cr[]) {
159 int i, szq;
160
161 szq = max(m - n + 1, 1);
162 for (i = 0; i < szq; i++) {
163 if (q[i] != cq[i]) {
164 errors = errors + 1;
165 dumpit("Error, dividend u =", m, u);
166 dumpit(" divisor v =", n, v);
167 dumpit("For quotient, got:", m-n+1, q);
168 dumpit(" Should get:", m-n+1, cq);
169 return;
170 }
171 }
172 for (i = 0; i < n; i++) {
173 if (r[i] != cr[i]) {
174 errors = errors + 1;
175 dumpit("Error, dividend u =", m, u);
176 dumpit(" divisor v =", n, v);
177 dumpit("For remainder, got:", n, r);
178 dumpit(" Should get:", n, cr);
179 return;
180 }
181 }
182 return;
183 }
184
185 int main() {
186 static unsigned test[] = {
187 // m, n, u..., v..., cq..., cr....
188 1, 1, 3, 0, 1, 1, // Error, divide by 0.
189 1, 2, 7, 1,3, 0, 7,0, // Error, n > m.
190 2, 2, 0,0, 1,0, 0, 0,0, // Error, incorrect remainder cr.
191 1, 1, 3, 2, 1, 1,
192 1, 1, 3, 3, 1, 0,
193 1, 1, 3, 4, 0, 3,
194 1, 1, 0, 0xffffffff, 0, 0,
195 1, 1, 0xffffffff, 1, 0xffffffff, 0,
196 1, 1, 0xffffffff, 0xffffffff, 1, 0,
197 1, 1, 0xffffffff, 3, 0x55555555, 0,
198 2, 1, 0xffffffff,0xffffffff, 1, 0xffffffff,0xffffffff, 0,
199 2, 1, 0xffffffff,0xffffffff, 0xffffffff, 1,1, 0,
200 2, 1, 0xffffffff,0xfffffffe, 0xffffffff, 0xffffffff,0, 0xfffffffe,
201 2, 1, 0x00005678,0x00001234, 0x00009abc, 0x1e1dba76,0, 0x6bd0,
202 2, 2, 0,0, 0,1, 0, 0,0,
203 2, 2, 0,7, 0,3, 2, 0,1,
204 2, 2, 5,7, 0,3, 2, 5,1,
205 2, 2, 0,6, 0,2, 3, 0,0,
206 1, 1, 0x80000000, 0x40000001, 0x00000001, 0x3fffffff,
207 2, 1, 0x00000000,0x80000000, 0x40000001, 0xfffffff8,0x00000001, 0x00000008,
208 2, 2, 0x00000000,0x80000000, 0x00000001,0x40000000, 0x00000001, 0xffffffff,0x3fffffff,
209 2, 2, 0x0000789a,0x0000bcde, 0x0000789a,0x0000bcde, 1, 0,0,
210 2, 2, 0x0000789b,0x0000bcde, 0x0000789a,0x0000bcde, 1, 1,0,
211 2, 2, 0x00007899,0x0000bcde, 0x0000789a,0x0000bcde, 0, 0x00007899,0x0000bcde,
212 2, 2, 0x0000ffff,0x0000ffff, 0x0000ffff,0x0000ffff, 1, 0,0,
213 2, 2, 0x0000ffff,0x0000ffff, 0x00000000,0x00000001, 0x0000ffff, 0x0000ffff,0,
214 3, 2, 0x000089ab,0x00004567,0x00000123, 0x00000000,0x00000001, 0x00004567,0x00000123, 0x000089ab,0,
215 3, 2, 0x00000000,0x0000fffe,0x00008000, 0x0000ffff,0x00008000, 0xffffffff,0x00000000, 0x0000ffff,0x00007fff, // Shows that first qhat can = b + 1.
216 3, 3, 0x00000003,0x00000000,0x80000000, 0x00000001,0x00000000,0x20000000, 0x00000003, 0,0,0x20000000, // Adding back step req'd.
217 3, 3, 0x00000003,0x00000000,0x00008000, 0x00000001,0x00000000,0x00002000, 0x00000003, 0,0,0x00002000, // Adding back step req'd.
218 4, 3, 0,0,0x00008000,0x00007fff, 1,0,0x00008000, 0xfffe0000,0, 0x00020000,0xffffffff,0x00007fff, // Add back req'd.
219 4, 3, 0,0x0000fffe,0,0x00008000, 0x0000ffff,0,0x00008000, 0xffffffff,0, 0x0000ffff,0xffffffff,0x00007fff, // Shows that mult-sub quantity cannot be treated as signed.
220 4, 3, 0,0xfffffffe,0,0x80000000, 0x0000ffff,0,0x80000000, 0x00000000,1, 0x00000000,0xfffeffff,0x00000000, // Shows that mult-sub quantity cannot be treated as signed.
221 4, 3, 0,0xfffffffe,0,0x80000000, 0xffffffff,0,0x80000000, 0xffffffff,0, 0xffffffff,0xffffffff,0x7fffffff, // Shows that mult-sub quantity cannot be treated as signed.
222 };
223 int i, n, m, ncases, f;
224 unsigned q[10], r[10];
225 unsigned *u, *v, *cq, *cr;
226
227 printf("divmnu:\n");
228 i = 0;
229 ncases = 0;
230 while (i < sizeof(test)/4) {
231 m = test[i];
232 n = test[i+1];
233 u = &test[i+2];
234 v = &test[i+2+m];
235 cq = &test[i+2+m+n];
236 cr = &test[i+2+m+n+max(m-n+1, 1)];
237
238 f = divmnu(q, r, u, v, m, n);
239 if (f) {
240 dumpit("Error return code for dividend u =", m, u);
241 dumpit(" divisor v =", n, v);
242 errors = errors + 1;
243 }
244 else
245 check(q, r, u, v, m, n, cq, cr);
246 i = i + 2 + m + n + max(m-n+1, 1) + n;
247 ncases = ncases + 1;
248 }
249
250 printf("%d errors out of %d cases; there should be 3.\n", errors, ncases);
251 return 0;
252 }