root/trunk/etc/bigint/bigint_int.d

Revision 37, 32.6 kB (checked in by brad, 4 years ago)

incorporated Stewart Gordon's patches for radix and bigint_int

Line 
1 module etc.bigint.bigint_int;
2 import etc.bigint.exception;
3 import etc.bigint.multiply;
4 import etc.bigint.radix;
5 private import std.c.stdlib;
6 private import std.math;
7 private import std.string;
8
9 /*
10
11 Copyright (c) 2004, Arcane Jill
12
13 All rights reserved. Intellectual Property Me Arse!
14
15 Redistribution and use in source and binary forms, with or without modification, are permitted
16 provided that the following conditions are met:
17
18    * Redistributions of source code must retain the above copyright notice, the phrase
19      "Intellectual Property Me Arse!", this list of conditions, and the following disclaimer.
20    * Redistributions in binary form must reproduce the above copyright notice, the phrase
21      "Intellectual Property Me Arse!", this list of conditions and the following disclaimer
22      in the documentation and/or other materials provided with the distribution.
23    * The name Arcane Jill may not be used to endorse or promote products derived from this
24      software without specific prior written permission.
25
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
27 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
28 AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER,
29 OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED, AND ON ANY
32 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
33 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
34 OF SUCH DAMAGE.
35
36 */
37
38 class Int
39 {
40     unittest
41     {
42         Int a,b,c,d;
43
44         //------------------------------------------
45         // Test comparisons
46         a = new Int(0xAAAAAAAA);
47         b = new Int(0xAAAAAAAA);
48         c = new Int(0xCCCCCCCC);
49         d = new Int("0x00000001AAAAAAAA");
50         assert(a == b);
51         assert(a < c);
52         assert(c > a);
53         assert(a < d);
54         assert(d > a);
55         d = new Int(-1);
56         assert(d < a);
57
58         //------------------------------------------
59         // Test add and subtract
60         a = b + c;
61         d = new Int("0x0000000177777776");
62         assert(a == d);
63         assert(a - b == c);
64         c = -d;
65         assert(c+d == 0);
66
67         //------------------------------------------
68         // Test multiply and divide for small values
69         a = new Int(0x11111111);
70         a = -a;
71         b = a * a;
72         c = new Int("0x0123456787654321");
73         assert(b == c);
74         b = b / a;
75         assert(b == a);
76         a = new Int(22);
77         assert(a / 7 == 3);
78         assert(a % 7 == 1);
79         assert(a / -7 == -3);
80         assert(a % -7 == 1);
81         a = -a;
82         assert(a / 7 == -3);
83         assert(a % 7 == -1);
84         assert(a / -7 == 3);
85         assert(a % -7 == -1);
86         a = -a;
87         b = new Int(7);
88         c = -b;
89         assert(divMod(a, b, d, Round.TOWARD_MINUS_INFINITY) == 3);
90         assert(d == 1);
91         assert(divMod(a, c, d, Round.TOWARD_MINUS_INFINITY) == -4);
92         assert(d == -6);
93         a = -a;
94         assert(divMod(a, b, d, Round.TOWARD_MINUS_INFINITY) == -4);
95         assert(d == 6);
96         assert(divMod(a, c, d, Round.TOWARD_MINUS_INFINITY) == 3);
97         assert(d == -1);
98
99         //------------------------------------------
100         // Test multiply and divide for large values
101         a = new Int("0x0111111111111111");
102         b = a * a;
103         c = new Int("0x000123456789ABCDEFEDCBA987654321");
104         assert(b == c);
105         b = b / a;
106         assert(b == a);
107
108         //------------------------------------------
109         // Test binary operations
110         a = new Int("0x1234567812345678");
111         uint n = a & 0xFFFFu;
112         assert(n == 0x5678);
113         b = a & new Int(0xFF00FF);
114         assert(b == new Int(0x340078));
115         c = a | 0xFFFF;
116         assert(c == new Int("0x123456781234FFFF"));
117         d = a ^ 0xFFFFFFFF;
118         assert (d == new Int("0x12345678EDCBA987"));
119         c = d & -1;
120         assert(c == d);
121         c = ~d;
122         assert((c ^ (-1)) == d);
123
124         //------------------------------------------
125         // Test shift left and shift right
126         a = new Int(0x12345678);
127         b = a << 40;
128         c = new Int("0x000000123456780000000000");
129         assert(b == c);
130         d = c << -40;
131         assert(d == a);
132         d = c >>> 40;
133         assert(d == a);
134         c = -c;
135         a = -a;
136         d = c << -40;
137         assert(d == a);
138         try
139         {
140             d = c >>> 40;
141         }
142         catch (IntException)
143         {
144             b = ZERO;
145         }
146         assert(b == 0);
147         d = c >>> 0;
148         assert(c == d);
149
150         //------------------------------------------
151         // Test the array-like functions
152
153         a = new Int("0xFEDCBA98_76543210_00000000_00000000_FEDCBA98_76543210");
154         assert(a[1] == 0xFEDCBA98);
155         assert(a[3000] == 0);
156         assert(a[0..2] == a[4..6]);
157         assert(a[100..115] == a[200..215]);
158         assert(a[0..4] == a[4..8]);
159
160         //------------------------------------------
161         // Test formatting
162
163         a = new Int(123);
164         assert(a.format(10, 0, 0, false, SignMode.NORMAL)           ==   "123");
165         assert(a.format(10, 0, 0, false, SignMode.MINUS_SPACE_PLUS) ==  "+123");
166         assert(a.format(10, 0, 0, true,  SignMode.NORMAL)           ==   "123");
167         assert(a.format(10, 0, 2, false, SignMode.NORMAL)           ==  "1_23");
168         assert(a.format(10, 5, 0, false, SignMode.NORMAL)           == "  123");
169         assert(a.format(10, 5, 0, false, SignMode.MINUS_SPACE_PLUS) == " +123");
170         assert(a.format(10, 5, 0, true,  SignMode.NORMAL)           == "00123");
171         assert(a.format(10, 5, 0, true,  SignMode.MINUS_SPACE_PLUS) == "+0123");
172         assert(a.format(10, 5, 2, false, SignMode.NORMAL)           == " 1_23");
173         a = -a;
174         assert(a.format(10, 5, 0, false, SignMode.NORMAL)           == " -123");
175         assert(a.format(10, 5, 0, true,  SignMode.NORMAL)           == "-0123");
176         assert(a.format(10, 5, 2, false, SignMode.NORMAL)           == "-1_23");
177
178         a = new Int("123456");
179         assert(a.toString() == "123456");
180         a = new Int("0x123456");
181         assert(a.toHexString() == "123456");
182
183         a = new Int("0");
184         assert (a.toString == "0");
185         assert (ZERO.toString == "0");
186         assert (a == ZERO);
187         assert (a == new Int(0));
188     }
189
190     invariant
191     {
192         if (d)
193         {
194             uint n = d.length;
195             assert(n >= 2);                 // array must be sufficiently large (2 uints)
196             int s = d[n-1];
197             assert((s == 0) || (s == -1));  // sign field may not contain rubbish
198             if (n>2)
199             {
200                 assert(d[n-2] != s);        // array must be minimal
201             }
202         }
203     }
204
205     public
206     {
207
208         // -------- Constants --------
209
210         enum Round { TOWARD_ZERO, TOWARD_INFINITY, TOWARD_MINUS_INFINITY }
211
212         static
213         {
214             Int ZERO, ONE, TWO, MINUS_ONE;
215         }
216
217         static this()
218         {
219             ZERO = new Int(0);
220             ONE = new Int(1);
221             TWO = new Int(2);
222             MINUS_ONE = new Int(-1);
223         }
224
225         // -------- Constructors --------
226
227         // Construct from an int
228         this(int n)
229         {
230             d.length = 2;
231             d[0] = n;
232             d[1] = n < 0 ? -1U : 0;
233         }
234
235         static Int opCall(int n) { return new Int(n); }
236
237         // Construct from a uint
238         this(uint n)
239         {
240             d.length = 2;
241             d[0] = n;
242         }
243
244         static Int opCall(uint n) { return new Int(n); }
245
246         // Construct from a long
247         this(long n)
248         {
249             d.length = 3;
250             *(cast(ulong*)d) = n;
251             d[2] = n < 0 ? -1U : 0;
252             minimize(this);
253         }
254
255         static Int opCall(long n) { return new Int(n); }
256
257         // Construct from a ulong
258         this(ulong n)
259         {
260             d.length = 3;
261             *(cast(ulong*)d) = n;
262             minimize(this);
263         }
264
265         static Int opCall(ulong n) { return new Int(n); }
266
267         // Construct from a float
268         this(float x)
269         {
270             this(cast(real) x);
271         }
272
273         static Int opCall(float x) { return new Int(x); }
274
275         // Construct from a double
276         this(double x)
277         {
278             this(cast(real) x);
279         }
280
281         static Int opCall(double x) { return new Int(x); }
282
283         // Construct from a real
284         this(real x)
285         {
286             uint i;
287             d.length = 4;
288             bool sign = (x < 0);
289             if (sign) x = -x;
290             while (x > 0)
291             {
292                 real xq = floor(x / 4294967296.0);
293                 real xr = x - (xq * 4294967296.0);
294                 d[i++] = cast(uint) xr;
295                 if (i == d.length-1) d.length = d.length << 1;
296                 x = xq;
297             }
298             if (sign)
299             {
300                 bigintLLNeg(d, d, d.length);
301             }
302             minimize(this);
303         }
304
305         static Int opCall(real x) { return new Int(x); }
306
307         // Construct from a string.
308         this(char[] s)
309         {
310             this(s, uint.max);
311         }
312
313         static Int opCall(char[] s) { return new Int(s); }
314
315         this(char[] s, uint radix)
316         {
317             bool isNegative = false;
318             if (s.length > 1)
319             {
320                 if (s[0] == '+')
321                 {
322                     s = s[1..s.length];
323                 }
324                 else if (s[0] == '-')
325                 {
326                     s = s[1..s.length];
327                     isNegative = true;
328                 }
329             }
330             d = bigintFromString(s, radix);
331
332             uint len = bigintLLMinimize(d, d.length);
333             if (len == 0)
334             {
335                 d.length = 2;
336                 d[] = isNegative ? -1U : 0;
337             }
338             else
339             {
340                 d.length = len+1;
341             }
342             if (isNegative)
343             {
344                 bigintLLNeg(d, d, d.length);
345                 minimize(this);
346             }
347         }
348
349         static Int opCall(char[] s, uint radix) { return new Int(s, radix); }
350
351         // Construct from a uint array. This copies by value, not by reference;
352         this(uint[] x, bool isNegative)
353         {
354             d.length = x.length + 1;
355             d[0..x.length] = x[0..x.length];
356             d[x.length] = isNegative ? -1U : 0;
357             minimize(this);
358         }
359
360         static Int opCall(uint[] x, bool isNegative) { return new Int(x, isNegative); }
361
362         // -------- Conversions --------
363
364         override
365         {
366             char[] toString()
367             out(s)
368             {
369                 assert(this == new Int(s));
370             }
371             body
372             {
373                 return format(10, 0, 0, false, SignMode.NORMAL);
374             }
375         }
376
377         char[] toHexString()
378         out(s)
379         {
380             assert(this == new Int(s,16));
381         }
382         body
383         {
384             return format(16, 0, 8, false, SignMode.NORMAL);
385         }
386
387         int toInt()
388         {
389             if (isInt()) return d[0];
390             return (sign) ? int.min : int.max;
391         }
392
393         uint toUint()
394         {
395             if (isUint()) return d[0];
396             return uint.max;
397         }
398
399         long toLong()
400         {
401             if (isLong())
402             {
403                 ulong lo = d[0];
404                 ulong hi = d[1];
405                 return (hi << 32) | lo;
406             }
407             return (sign) ? long.min : long.max;
408         }
409
410         ulong toUlong()
411         {
412             if (isUlong())
413             {
414                 ulong lo = d[0];
415                 ulong hi = d[1];
416                 return (hi << 32) | lo;
417             }
418             return ulong.max;
419         }
420
421         float toFloat()
422         {
423             return toReal();
424         }
425
426         double toDouble()
427         {
428             return toReal();
429         }
430
431         real toReal()
432         {
433             if (sign) return -((-this).toReal());
434             real r = 0;
435             for (uint i=0; i<end; ++i)
436             {
437                 r *= 4294967296.0;
438                 r += d[i];
439             }
440             return r;
441         }
442
443         // -------- Tests --------
444
445         bool isInt()
446         {
447             if (d.length > 2) return false;
448             if (sign)
449             {
450                 return (d[0] >= 0x80000000);
451             }
452             else
453             {
454                 return (d[0] < 0x80000000);
455             }
456         }
457
458         bool isUint()
459         {
460             if (sign) return false;
461             return (d.length == 2);
462         }
463
464         bool isLong()
465         {
466             if (d.length > 3) return false;
467             if (sign)
468             {
469                 return (d[d.length-2] >= 0x80000000);
470             }
471             else
472             {
473                 return (d[d.length-2] < 0x80000000);
474             }
475         }
476
477         bool isUlong()
478         {
479             if (sign) return false;
480             return (d.length <= 3);
481         }
482
483         override
484         {
485             int /*I wish this was bool*/ opEquals(Object obj)
486             {
487                 Int y = cast(Int) obj;
488                 assert(y);
489                 return d == y.d;
490             }
491         }
492
493         int /*I wish this was bool*/ opEquals(int n)
494         {
495             return isInt() ? (n == d[0]) : 0;
496         }
497
498         int /*I wish this was bool*/ opEquals(uint n)
499         {
500             return isUint() ? (n == d[0]) : 0;
501         }
502
503         override
504         {
505             int opCmp(Object obj)
506             {
507                 Int y = cast(Int) obj;
508                 assert(y);
509
510                 Int x = this;
511                 if (x === y) return 0;
512                 int xSign = x.sign;
513                 int ySign = y.sign;
514                 if (xSign < ySign) return -1;
515                 if (xSign > ySign) return 1;
516
517                 int r;
518                 int n = x.d.length;
519                 if (x.d.length > y.d.length)
520                 {
521                     n = y.d.length;
522                     r = bigintLLCmpAll(&x.d[y.d.length], y.sign, x.d.length - y.d.length);
523                     if (r < 0) return -1;
524                     if (r > 0) return 1;
525                 }
526                 if (x.d.length < y.d.length)
527                 {
528                     r = bigintLLCmpAll(x.sign, &y.d[x.d.length], y.d.length - x.d.length);
529                     if (r < 0) return -1;
530                     if (r > 0) return 1;
531                 }
532                 r = bigintLLCmp(x.d, y.d, n);
533                 if (r < 0) return -1;
534                 if (r > 0) return 1;
535                 return 0;
536             }
537         }
538
539         int opCmp(int y)
540         {
541             if (isInt())
542             {
543                 int x = d[0];
544                 if (x == y) return 0;
545                 return (x < y) ? -1 : 1;
546             }
547             else
548             {
549                 return opCmp(new Int(y));
550             }
551         }
552
553         int opCmp(uint y)
554         {
555             if (isUint())
556             {
557                 uint x = d[0];
558                 if (x == y) return 0;
559                 return (x < y) ? -1 : 1;
560             }
561             else
56