root/trunk/etc/bigint/lowlevel.d

Revision 12, 12.6 kB (checked in by Arcane Jill, 8 years ago)

--

Line 
1 module etc.bigint.lowlevel;
2 import std.intrinsic;
3 /*
4
5 Copyright (c) 2004, Arcane Jill
6
7 All rights reserved. Intellectual Property Me Arse!
8
9 Redistribution and use in source and binary forms, with or without modification, are permitted
10 provided that the following conditions are met:
11
12    * Redistributions of source code must retain the above copyright notice, the phrase
13      "Intellectual Property Me Arse!", this list of conditions, and the following disclaimer.
14    * Redistributions in binary form must reproduce the above copyright notice, the phrase
15      "Intellectual Property Me Arse!", this list of conditions and the following disclaimer
16      in the documentation and/or other materials provided with the distribution.
17    * The name Arcane Jill may not be used to endorse or promote products derived from this
18      software without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
21 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22 AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER,
23 OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED, AND ON ANY
26 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
28 OF SUCH DAMAGE.
29
30 */
31
32 /*
33
34 The functions in this file have no concept of an Int object, and they do
35 not deal in arrays of uints. Instead, they take raw pointers into arrays of uints,
36 along with an explicit length parameter. The uints pointed to are interpretted as
37 an UNSIGNED multi-precision integer.
38
39 */
40
41 /*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
42 d = x + y
43 */
44
45 // Add two unsigned bigints of different sizes
46 uint bigintLLAdd(uint* d, uint* x, uint xLen, uint* y, uint yLen)
47 in
48 {
49     assert(xLen >= yLen);
50 }
51 body
52 {
53     uint carry = bigintLLAdd(d, x, y, yLen);
54     return bigintLLInc(d+yLen, x+yLen, carry, xLen-yLen);
55 }
56
57 // Add two unsigned bigints of the same size
58 uint bigintLLAdd(uint* d, uint* x, uint* y, uint len)
59 {
60     uint carry;
61     ulong xVal, dVal;
62     for (int i=len-1; i>=0; --i)
63     {
64         xVal = *x++;
65         dVal = xVal + *y++ + carry;
66         carry = dVal > 0xFFFFFFFF;
67         *d++ = dVal;
68     }
69     return carry;
70 }
71
72 /*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
73 d = x & y
74 */
75
76 void bigintLLAnd(uint* d, uint* x, uint* y, uint len)
77 {
78     for (int i=len-1; i>=0; --i)
79     {
80         *d++ = *x++ & *y++;
81     }
82 }
83
84 /*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
85 d = x
86 */
87
88 void bigintLLAssign(uint* d, uint* x, uint len)
89 {
90     for (int i=len-1; i>=0; --i)
91     {
92         *d++ = *x++;
93     }
94 }
95
96 /*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
97 Compare two bigints of the same length
98 */
99
100 int bigintLLCmp(uint* x, uint* y, uint len)
101 {
102     for (int i=len-1; i>=0; --i)
103     {
104         if (x[i] < y[i]) return -1;
105         if (x[i] > y[i]) return  1;
106     }
107     return 0;
108 }
109
110 /*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
111 Compare two bigints of different lengths
112 */
113
114 int bigintLLCmp(uint* x, uint xLen, uint* y, uint yLen)
115 {
116     // Get the longest seqence into x
117     bool swapped = (xLen < yLen);
118     if (swapped)
119     {
120         uint* t = x;
121         x = y;
122         y = t;
123         uint tLen = xLen;
124         xLen = yLen;
125         yLen = tLen;
126     }
127
128     // See if the high order part of x is zero
129     if (!bigintLLEqualsZero(x+yLen, xLen-yLen))
130     {
131         return (swapped) ? -1 : 1;
132     }
133
134     // Compare the low order parts
135     int n = bigintLLCmp(x, y, yLen);
136     return (swapped) ? -n : n;
137 }
138
139 /*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
140 Compare all words of an bigint with a single value
141 */
142
143 int bigintLLCmpAll(uint* x, uint y, uint len)
144 {
145     for (int i=len-1; i>=0; --i)
146     {
147         if (x[i] < y) return -1;
148         if (x[i] > y) return  1;
149     }
150     return 0;
151 }
152
153 int bigintLLCmpAll(uint x, uint* y, uint len)
154 {
155     return -bigintLLCmpAll(y, x, len);
156 }
157
158 /*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
159 d = ~x
160 */
161 void bigintLLCom(uint* d, uint* x, uint len)
162 {
163     for (int i=len-1; i>=0; --i)
164     {
165         *d++ = ~(*x++);
166     }
167 }
168
169 /*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
170     d = x - carry
171     (carry may by in the range 0 <= carry < 0xFFFFFFFF)
172 */
173 uint bigintLLDec(uint* d, uint* x, uint carry, uint len)
174 {
175     return bigintLLDecV(d, x, 0, carry, len);
176 }
177
178 uint bigintLLDecV(uint* d, uint* x, uint y, uint carry, uint len)
179 in
180 {
181     assert(y == 0 || y == uint.max);
182 }
183 body
184 {
185     ulong xVal, dVal;
186     for (int i=len-1; i>=0; --i)
187     {
188         xVal = *x++;
189         dVal = xVal - y - carry;
190         carry = dVal > 0xFFFFFFFF;
191         *d++ = dVal;
192     }
193     return carry;
194 }
195
196 /*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
197 d = x / n
198 carry = x % n
199 */
200 uint bigintLLDiv(uint* d, uint* x, uint k, uint len)
201 {
202     uint carry, xVal, dVal;
203     d += len;
204     x += len;
205     for (int i=len-1; i>=0; --i)
206     {
207         xVal = *--x;
208         version(X86)
209         {
210             asm
211             {
212                 mov EDX,carry;
213                 mov EAX,xVal;
214                 mov EBX,k;
215                 div EBX;
216                 mov dVal,EAX;
217                 mov carry,EDX;
218             }
219         }
220         else
221         {
222             ulong val = (cast(ulong)carry)<<32 | xVal;
223             dVal = val / k;
224             carry = val - dVal * k;
225         }
226         *--d = dVal;
227     }
228     return carry;
229 }
230
231 /*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
232 q = x / n
233 r = x % n
234 */
235 void bigintDivMod(uint* q, uint qLen, uint* r, uint rLen, uint* x, uint xLen, uint* y, uint yLen)
236 in
237 {
238     assert(xLen >= yLen);
239     assert(qLen >= xLen - yLen + 1);
240     assert(rLen >= yLen);
241 }
242 body
243 {
244     // Normalize the operands x and y into xx and yy
245     // and ensure that the xx bigintLL is big enough to hold the working data
246     uint[] xx, yy, zz;
247     xx.length = xLen + yLen + 1;
248     yy.length = yLen;
249     zz.length = yLen + 1;
250     uint yHi = y[yLen - 1];
251     uint shiftCount = 31 - bsr(yHi);
252     bigintLLShl(yy, y, shiftCount, yLen);
253     xx[xLen] = bigintLLShl(xx, x, shiftCount, xLen);
254
255     // Zero the quotient
256     bigintLLZero(q, qLen);
257
258     // Now do the long division
259     yHi = yy[yLen-1];
260     for (int i=qLen-1; i>=0; --i)
261     {
262         // First, we ESTIMATE the next most significant uint of the result (q)
263         uint qi; // This is going to be an estimate of q[i];
264         if (yHi == 0xFFFFFFFF)
265         {
266             qi = xx[yLen+i];
267         }
268         else
269         {
270             uint xHi = xx[yLen+i];
271             uint xLo = xx[yLen+i-1];
272             uint d = yHi + 1;
273             version(X86)
274             {
275                 asm
276                 {
277                     mov EDX,xHi;
278                     mov EAX,xLo;
279                     mov EBX,d;
280                     div EBX;
281                     mov qi,EAX;
282                 }
283             }
284             else
285             {
286                 ulong x = ((cast(ulong) xHi) << 32) | xLo;
287                 qi = x / d;
288             }
289         }
290
291         // Assuming qi to be correct, churn out the next row of the long division
292         zz[yLen] = bigintLLMul(zz, yy, qi, yLen);
293         bigintLLSub(&xx[i], &xx[i], zz, yLen+1);
294
295         // Of course, qi may not have been correct.
296         // So now we need to fix our estimate
297         while ((xx[yLen+i] != 0) || (bigintLLCmp(&xx[i], yy, yLen) >= 0))
298         {
299             ++qi;
300             xx[yLen+i] -= bigintLLSub(&xx[i], &xx[i], yy, yLen);
301         }
302
303         // We have the next uint. Store it.
304         q[i] = qi;
305     }
306
307     // We have now got the quotient in q.
308     // All we have to do now is get the remainder.
309     bigintLLShr(r, xx, shiftCount, yLen);
310
311     // And for the security conscious...
312     xx[] = 0;
313     yy[] = 0;
314     zz[] = 0;
315 }
316
317 /*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
318 Tests whether two bigints are equal
319 */
320 bool bigintLLEquals(uint* x, uint* y, uint len)
321 {
322     for (int i=len-1; i>=0; --i)
323     {
324         if (*x++ != *y++) return false;
325     }
326     return true;
327 }
328
329 /*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
330 Tests whether an bigint uint is zero
331 */
332 bool bigintLLEqualsZero(uint* x, uint len)
333 {
334     for (int i=len-1; i>=0; --i)
335     {
336         if (*x++ != 0) return false;
337     }
338     return true;
339 }
340
341 /*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
342 Counts the number of 1 bits in a bigint
343 */
344 uint bigintLLCountOnes(uint* x, uint len)
345 {
346     uint n = 0;
347     for (int i=len-1; i>=0; --i)
348     {
349         uint xVal = *x++;
350         if (xVal == 0) continue;
351         for (uint j=0x80000000; j!=0; j>>>=1)
352         {
353             if ((xVal & j) != 0) ++n;
354         }
355     }
356     return n;
357 }
358
359 /*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
360     d = x + carry
361     (carry may by in the range 0 <= carry < 0xFFFFFFFF)
362 */
363 uint bigintLLInc(uint* d, uint* x, uint carry, uint len)
364 {
365     return bigintLLIncV(d, x, 0, carry, len);
366 }
367
368 uint bigintLLIncV(uint* d, uint* x, uint y, uint carry, uint len)
369 in
370 {
371     assert(y == 0 || y == uint.max);
372 }
373 body
374 {
375     ulong xVal, dVal;
376     for (int i=len-1; i>=0; --i)
377     {
378         xVal = *x++;
379         dVal = xVal + y + carry;
380         carry = dVal > 0xFFFFFFFF;
381         *d++ = dVal;
382     }
383     return carry;
384 }
385
386 /*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
387 Find the minimal storage required for an bigint uint
388 */
389 uint bigintLLMinimize(uint* x, uint len)
390 {
391     return bigintLLMinimizeV(x, 0, len);
392 }
393
394 uint bigintLLMinimizeV(uint* x, uint y, uint len)
395 {
396     for (; len>0; --len)
397     {
398         if (x[len-1] != y) break;
399     }
400     return len;
401 }
402
403 /*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
404 d = x * k
405 */
406 uint bigintLLMul(uint* d, uint* x, uint k, uint len)
407 {
408     uint carry, xVal, dVal;
409     for (int i=len-1; i>=0; --i)
410     {
411         xVal = *x++;
412         version(X86)
413         {
414             asm
415             {
416                 mov EAX,xVal;
417                 mov EBX,k;
418                 mul EBX;
419                 add EAX,carry;
420                 adc EDX,0;
421                 mov carry,EDX;
422                 mov dVal,EAX;
423             }
424         }
425         else
426         {
427             ulong dVal = cast(ulong)xVal * cast(ulong)k + carry;
428             carry = (dVal >> 32);
429         }
430         *d++ = dVal;
431     }
432     return carry;
433 }
434
435 /*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
436 d = -x
437 */
438
439 uint bigintLLNeg(uint* d, uint* x, uint len)
440 {
441     uint carry;
442     ulong xVal, dVal;
443     for (int i=len-1; i>=0; --i)
444     {
445         xVal = *x++;
446         dVal = 0 - xVal - carry;
447         carry = dVal > 0xFFFFFFFF;
448         *d++ = dVal;
449     }
450     return carry;
451 }
452
453 /*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
454 d = x & y
455 */
456
457 void bigintLLOr(uint* d, uint* x, uint* y, uint len)
458 {
459     for (int i=len-1; i>=0; --i)
460     {
461         *d++ = *x++ | *y++;
462     }
463 }
464
465 /*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
466 d = x << n
467 */
468 uint bigintLLShl(uint* d, uint* x, uint k, uint len)
469 {
470     if (k == 0)
471     {
472         bigintLLAssign(d, x, len);
473         return 0;
474     }
475     uint carry, xVal;
476     ulong dVal;
477     for (int i=len-1; i>=0; --i)
478     {
479         xVal = *x++;
480         dVal = (cast(ulong)xVal << k) | carry;
481         carry = (dVal >> 32);
482         *d++ = cast(uint) dVal;
483     }
484     return carry;
485 }
486
487
488 /*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
489 d = x >>> n
490 */
491 uint bigintLLShr(uint* d, uint* x, uint k, uint len)
492 {
493     if (k == 0)
494     {
495         bigintLLAssign(d, x, len);
496         return 0;
497     }
498     ulong carry;
499     uint xVal, dVal;
500     d += len;
501     x += len;
502     for (int i=len-1; i>=0; --i)
503     {
504         xVal = *--x;
505         carry <<= 32;
506         carry |= xVal;
507         dVal = cast(uint) (carry >> k);
508         carry = xVal;
509         *--d = dVal;
510     }
511     return carry << (32-k);
512 }
513
514 /*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
515 d = x - y
516 */
517 // Subtract two unsigned bigints of different sizes
518 uint bigintLLSub(uint* d, uint* x, uint xLen, uint* y, uint yLen)
519 in
520 {
521     assert(xLen >= yLen);
522 }
523 body
524 {
525     uint carry = bigintLLSub(d, x, y, yLen);
526     return bigintLLDec(d+yLen, x+yLen, carry, xLen-yLen);
527 }
528
529 // Subtract two unsigned bigints of the same size
530 uint bigintLLSub(uint* d, uint* x, uint* y, uint len)
531 {
532     uint carry;
533     ulong xVal, dVal;
534     for (int i=len-1; i>=0; --i)
535     {
536         xVal = *x++;
537         dVal = xVal - *y++ - carry;
538         carry = dVal > 0xFFFFFFFF;
539         *d++ = dVal;
540     }
541     return carry;
542 }
543
544 /*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
545 d = x ^ y
546 */
547 void bigintLLXor(uint* d, uint* x, uint* y, uint len)
548 {
549     for (int i=len-1; i>=0; --i)
550     {
551         *d++ = *x++ ^ *y++;
552     }
553 }
554
555 /*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
556 d = 0
557 */
558 void bigintLLZero(uint* d, uint len)
559 {
560     for (int i=len-1; i>=0; --i)
561     {
562         *d++ = 0;
563     }
564 }
Note: See TracBrowser for help on using the browser.