root/trunk/bignum/bignum.d

Revision 72, 10.6 kB (checked in by BCS, 1 year ago)

fixed error in opDivAssign

Line 
1 import std.stdio;
2
3 /**
4     Author: Benjamin Shropshire (shro8822 AT drop_spam_this vandals dot uidaho edu)
5     Copyright: You may redistribute this as you see fit. Please don't clame it
6         as your own. THIS SOFTWARE HAS NO WARRANTY OR GUARANTEE OF ANY KIND.
7 */
8
9 debug
10 {
11     void main(){}
12     // Don Clugston's decimaldigit and itoa,
13     // see http://trac.dsource.org/projects/ddl/browser/trunk/meta/conv.d
14
15     template decimalDigit(int n)
16     {
17       const char[] decimalDigit = "0123456789"[n..n+1];
18     }
19
20     template itoa(long n)
21     {   
22       static if (n < 0)
23          const char[] itoa = "-" ~ itoa!(-n); 
24       else static if (n < 10)
25          const char[] itoa = decimalDigit!(n);
26       else
27          const char[] itoa = itoa!(n/10L) ~ decimalDigit!(n%10L);
28     }
29 }
30
31 unittest
32 {
33     BigNum!(5) tmp,add,sum;
34
35     tmp = uint.max;
36     assert(tmp.values[0] == uint.max, "set(uint) failed");
37     assert(tmp == uint.max, "opEqual(uint) false neg");
38     assert(tmp != 1, "opEqual(uint) false pos");
39
40     add = 1;
41     assert(add.values[0] == 1, "set(uint) failed");
42     assert(add == 1, "opEqual(uint) false neg");
43     assert(add != uint.max, "opEqual(uint) false pos");
44
45     tmp.values[1] = uint.max;
46
47     sum = tmp+add;
48     assert(sum.values[0] == 0, "low word failed");
49     assert(sum.values[1] == 0, "carry word failed");
50     assert(sum.values[2] == 1, "high word failed");
51
52     sum = tmp;
53     sum += add;
54     assert(sum.values[0] == 0, "low word failed");
55     assert(sum.values[1] == 0, "carry word failed");
56     assert(sum.values[2] == 1, "high word failed");
57
58     tmp.values[2] = tmp.values[0] = 0;
59     tmp.values[1] = 1;
60     sum = tmp - add;
61     assert(sum.values[0] == uint.max, "low word failed");
62     assert(sum.values[1] == 0, "borrow word failed");
63     assert(sum.values[2] == 0, "high word failed");
64
65     sum = tmp;
66     sum -= add;
67     assert(sum.values[0] == uint.max, "low word failed");
68     assert(sum.values[1] == 0, "borrow word failed");
69     assert(sum.values[2] == 0, "high word failed");
70
71     tmp.values[0] = uint.max;
72     tmp.values[1] = uint.max;
73
74     sum = tmp*tmp;
75
76     assert(sum.values[3] == uint.max);
77     assert(sum.values[2] == uint.max - 1);
78     assert(sum.values[1] == 0);
79     assert(sum.values[0] == 1);
80 }
81
82 template BigNum(uint size)
83 {
84     static if(size > 63) pragma(msg, "Ok, I'll try it. But don't say I didn't warn you!!!");
85
86     static if(size <= 0) static assert(false, "BigNum!(0) invalid");
87     else static if(size <= 2) static assert(false, "BigNum!(size<=2) unimplemented");
88     else alias build!(size, size-2, size-1) BigNum;
89 }
90
91 template build(uint size, uint i, V...)
92 {
93     static if(i==1)
94         alias use!(size, 1, V) build;
95     else
96         alias build!(size, i-1, i, V) build;
97 }
98
99 template use(uint size, V...)
100 {
101     struct use
102     {
103             //DMD0.174 seg-v for size > 73
104         static if(size > 73) pragma(msg, "You might have set a new world record!!!!");
105
106             // most likely fails of this doesn't hold.
107         static assert(0 == values.offsetof);
108         uint[size] values;
109
110         void Emit()
111         {
112             for(int i=size-1; i>0; i--)
113                 writef("%x:",values[i]);
114             writef("%x\n",values[0]);
115         }
116
117         void opAssign(uint val)
118         {
119             values[0] = val;
120             static if(size>1)
121                 foreach(inout v; values[1..$])
122                     v = 0;
123         }
124
125         bool opEquals(uint i)
126         {
127             if (values[0] != i) return false;
128             static if(size>1)
129                 foreach(inout v; values[1..$])
130                     if(v != 0) return false;
131             return true;
132         }
133
134         bool opEquals(use!(size, V)  i)
135         {
136             return i.values[] == values[];
137         }
138
139         use!(size, V) opAdd(use!(size, V) to)
140         {
141             uint* ths  = this.values.ptr;
142             uint* dest = to.values.ptr;
143                 // DON'T USE "this" after this line!!!!!!!
144             asm
145             {
146                 mov EAX, ths[0];
147                 mov EBX, dest[0];
148                 mov EDX, [EAX+0];
149                 add [EBX+0], EDX;
150             }
151             foreach(j,i; V)
152             {
153                 const uint off = V[j]*4;         // this is a work-around
154                 asm
155                 {
156                     mov EDX, [EAX+off];
157                     adc [EBX+off], EDX;
158                 }
159             }
160             return to;
161         }
162
163         use!(size, V) opSub(use!(size, V) to)
164         {
165             uint* ths  = this.values.ptr;
166             uint* dest = to.values.ptr;
167                 // DON'T USE "this" after this line!!!!!!!
168             asm
169             {               // dest = ths - dest
170                 mov EAX, ths[0];    // dest = *EAX - dest
171                 mov EBX, dest[0];   // dest = *EAX - *EBX
172
173                 mov EDX, [EAX+0];   // dest = EDX - *EBX
174                 sub EDX, [EBX+0];   // EDX = EDX - *EBX
175                 mov [EBX+0], EDX;   // *EBX
176                             // dest
177             }
178             foreach(j,i; V)
179             {
180                 const uint off = V[j]*4;     // this is a work-around
181                 asm
182                 {
183                                 // dest = ths - dest
184                                 // dest = *EAX - *EBX
185                     mov EDX, [EAX+off]; // dest = EDX - *EBX
186                     sbb EDX, [EBX+off]; // EDX = EDX - ECX
187                     mov [EBX+off], EDX; // *EBX
188                                 // dest
189                 }
190             }
191             return to;
192         }
193
194         use!(size, V) opMul(use!(size, V) to)
195         {
196             uint* ths  = this.values.ptr;
197             use!(size, V) ret;
198                 // DON'T USE "this" after this line!!!!!!!
199
200             // EDX:EAX  mul in/out
201             asm
202             {
203             // load values.ptr[0] -> ECX
204             mov ECX, ths[0];
205             mov ECX, [ECX];
206             // load to.values.ptr[0] -> EAX
207             mov EAX, to[0];
208             // EDX:EAX = mul(EAX, ECX)
209             imul ECX;
210             // load EAX -> ret.values[0]
211             mov ret[0], EAX;
212             // load EDX -> ret.values[1]
213             mov ret[1], EDX;
214             }
215
216             debug pragma(msg, itoa!(__LINE__)~": set ret[0] from ths[0] and to[0]");
217             debug pragma(msg, itoa!(__LINE__)~": set ret[1] from ths[0] and to[0]");
218
219
220             foreach(k,l; V)
221             {
222                 const uint InI = V[k];   // this is a work-around
223                 const uint DesI = InI;
224                 static if(DesI < size)
225                 {
226                     asm
227                     {
228         // this seems to index by 32b (I'm not sure I trust this)
229                     // load to.values.ptr[InI] -> EAX
230                     mov EAX, to[InI];
231                     // EDX:EAX = mul(EAX, ECX)
232                     imul ECX;
233
234                     // load ret.values[DesI] -> EBX
235                     mov EBX, ret[DesI];
236                     // EBX = add(EBX, EAX)
237                     add EBX, EAX;
238                     // load EBX -> ret.values[DesI]
239                     mov ret[DesI], EBX;
240                     }
241                     debug pragma(msg, itoa!(__LINE__)~": set ret["~itoa!(DesI)~"] from ths[0] and to["~itoa!(InI)~"]");
242
243                     static if(DesI+1 < size)
244                     {
245                         asm
246                         {
247                         // load ret.values[DesI+1] -> EBX
248                         mov EBX, ret[DesI+1];
249                         // EBX = adc(EBX, EDX)
250                         adc EBX, EDX;
251                         // load EBX -> ret.values[DesI+1]
252                         mov ret[DesI+1], EBX;
253                         }
254                         debug pragma(msg, itoa!(__LINE__)~": set ret["~itoa!(DesI+1)~"] from ths[0] and to["~itoa!(InI)~"]");
255                     }
256                 }
257             }
258
259             foreach(i,j; V)
260             {
261                     // get rank of this row
262                 const uint OutI = V[i];  // this is a work-around
263                 asm
264                 {
265                 // load values.ptr[OutI] -> ECX
266                 mov ECX, ths;
267                 mov ECX, [ECX+OutI];
268                 // load to.values.ptr[0] -> EAX
269                 mov EAX, to[0];
270                 // EDX:EAX = mul(EAX, ECX)
271                 imul ECX;
272
273                 // load ret.values[OutI] -> EBX
274                 mov EBX, ret[OutI];
275                 // EBX = add(EBX, EAX)
276                 add EBX, EAX;
277                 // load EBX -> ret.values[OutI]
278                 mov ret[OutI], EBX;
279                 }
280                 debug pragma(msg, itoa!(__LINE__)~": set ret["~itoa!(OutI)~"] from ths["~itoa!(OutI)~"] and to[0]");
281
282                 static if(OutI+1 < size)
283                 {
284                     asm
285                     {
286                     // load ret.values[OutI+1] -> EBX
287                     mov EBX, ret[OutI+1];
288                     // EBX = adc(EBX, EDX)
289                     adc EBX, EDX;
290                     // load EBX -> ret.values[OutI+1]
291                     mov ret[OutI+1], EBX;
292                             nop;
293                     }
294                     debug pragma(msg, itoa!(__LINE__)~": set ret["~itoa!(OutI+1)~"] from ths["~itoa!(OutI)~"] and to[0]");
295                 }
296
297                 foreach(k,l; V)
298                 {
299                     const uint InI = V[k];   // this is a work-around
300                     const uint DesI = OutI + InI;
301                     static if(DesI < size)
302                     {
303                         asm
304                         {
305                         // load to.values.ptr[InI] -> EAX
306                         mov EAX, to[InI];
307                         // EDX:EAX = mul(EAX, ECX)
308                         imul ECX;
309
310                         // load ret.values[DesI] -> EBX
311                         mov EBX, ret[DesI];
312                         // EBX = add(EBX, EAX)
313                         add EBX, EAX;
314                         // load EBX -> ret.values[DesI]
315                         mov ret[DesI], EBX;
316                         }
317                         debug pragma(msg, itoa!(__LINE__)~": set ret["~itoa!(DesI)~"] from ths["~itoa!(OutI)~"] and to["~itoa!(InI)~"]");
318
319                         static if(DesI+1 < size)
320                         {
321                             asm
322                             {
323                             // load ret.values[DesI+1] -> EBX
324                             mov EBX, ret[DesI+1];
325                             // EBX = adc(EBX, EDX)
326                             adc EBX, EDX;
327                             // load EBX -> ret.values[DesI+1]
328                             mov ret[DesI+1], EBX;
329                             }
330                             debug pragma(msg, itoa!(__LINE__)~": set ret["~itoa!(DesI+1)~"] from ths["~itoa!(OutI)~"] and to["~itoa!(InI)~"]");
331                         }
332                     }
333                 }
334             }
335             return ret;
336         }
337
338
339         use!(size, V) opDiv(uint by)
340         {
341             uint* ths  = this.values.ptr;
342             use!(size, V) ret;
343                 // DON'T USE "this" after this line!!!!!!!
344
345             asm
346             {
347                 // move by into divisor(ECX)
348                 mov ECX, by[0];
349                 // zero dividend.high(EDX)
350                 xor EDX, EDX;
351             }
352
353             foreach_reverse(j,i; V)
354             {
355                 const uint off = V[j]*4;         // this is a work-around
356                
357                 debug pragma(msg, itoa!(__LINE__)~": dividing place ["~itoa!(off)~"]");
358                 asm
359                 {
360                     // Load this.values[off] into dividend.low(EAX)
361                     mov EAX, ths[off];
362                     // divide dividend by divisor(ECX), leaving in quotient(EAX):remainder(EDX)
363                     div ECX;
364                     // move quotient(EAX) to ret.values[off]
365                     mov ret[off], EAX;
366                     // make remainder(EDX) be dividend.high(EDX)
367                     //     no op needed
368                 }
369             }
370             return ret;
371
372             debug pragma(msg, itoa!(__LINE__)~": dividing place [0]");
373             asm
374             {
375                 // Load this.values[0] into dividend.low(EAX)
376                 mov EAX, ths[0];
377                 // divide dividend by divisor(ECX), leaving in quotient(EAX):remainder(EDX)
378                 div ECX;
379                 // move quotient(EAX) to ret.values[0]
380                 mov ret[0], EAX;
381                 // discard remainder(EDX)
382             }
383
384         }
385
386         use!(size, V) opAddAssign(use!(size, V) to)
387         {
388             uint* ths  = this.values.ptr;
389             uint* dest = to.values.ptr;
390                 // DON'T USE "this" after this line!!!!!!!
391             asm
392             {
393                 mov EBX, ths[0];
394                 mov EAX, dest[0];
395                 mov EDX, [EAX+0];
396                 add [EBX+0], EDX;
397                 // no store needed because dest is memory
398             }
399             foreach(j,i; V)
400             {
401                 const uint off = V[j]*4;         // this is a work-around
402                 asm
403                 {
404                     mov EDX, [EAX+off];
405                     adc [EBX+off], EDX;
406                     // no store needed because dest is memory
407                 }
408             }
409             return to;
410         }
411
412         use!(size, V) opSubAssign(use!(size, V) to)
413         {
414             uint* ths  = this.values.ptr;
415             uint* dest = to.values.ptr;
416                 // DON'T USE "this" after this line!!!!!!!
417             asm
418             {
419                 mov EBX, ths[0];
420                 mov EAX, dest[0];
421                 mov EDX, [EAX+0];
422                 sub [EBX+0], EDX;
423                 // no store needed because dest is memory
424             }
425             foreach(j,i; V)
426             {
427                 const uint off = V[j]*4;         // this is a work-around
428                 asm
429                 {
430                     mov EDX, [EAX+off];
431                     sbb [EBX+off], EDX;
432                     // no store needed because dest is memory
433                 }
434             }
435             return to;
436         }
437
438         use!(size, V) opMulAssign(use!(size, V) to)
439         {
440             return *this = opMul(to);
441         }
442
443         use!(size, V) opDivAssign(uint to)
444         {
445             return *this = opDiv(to);
446         }
447     }
448 }
Note: See TracBrowser for help on using the browser.