Annotation of OpenXM_contrib/PHC/Ada/Math_Lib/Numbers/multprec_natural_numbers.adb, Revision 1.1.1.1
1.1 maekawa 1: with unchecked_deallocation;
2:
3: package body Multprec_Natural_Numbers is
4:
5: -- NOTES ON THE CHOICE OF REPRESENTATION AND IMPLEMENTATION :
6: -- 1) The base is decimal, for convenience of input/output.
7: -- Everything should remain correct if another base is chosen,
8: -- except of course the function "Decimal_Places".
9: -- The base is such that factor times the base is still a standard
10: -- natural number, so that standard arithmetic can be used.
11: -- 2) A natural number is implemented by means of a coefficient array.
12: -- The advantage over a linked-list representation is that the
13: -- coefficients can be accessed faster. The disadvantage of some
14: -- wasted storage is countered by the aim of implementing higher
15: -- precision floating-point numbers, where the mantissa is fixed.
16: -- 3) The usage of a pointer to access the coefficient vector permits
17: -- to have uniformity in input/output, since on input it is not
18: -- known in advance how long a natural number may be.
19: -- 4) A natural number n for which Empty(n) holds is considered as zero.
20:
21: fact : constant natural := 10;
22: expo : constant natural := 8;
23: the_base : constant natural := fact**expo;
24:
25: -- DATATRUCTURES :
26:
27: type Natural_Number_Rep ( size : natural ) is record
28: numb : Array_of_Naturals(0..size);
29: end record;
30:
31: -- AUXILIARY :
32:
33: function Size ( n : natural ) return natural is
34:
35: -- DESCRIPTION :
36: -- Determines the size of the natural number to represent n.
37:
38: acc : natural := the_base;
39:
40: begin
41: for i in 0..n loop
42: if n < acc
43: then return i;
44: else acc := acc*the_base;
45: end if;
46: end loop;
47: return n;
48: end Size;
49:
50: -- CREATORS :
51:
52: function Create ( n : natural ) return Array_of_Naturals is
53:
54: res : Array_of_Naturals(0..Size(n));
55: remainder : natural := n;
56:
57: begin
58: for i in res'range loop
59: res(i) := remainder mod the_base;
60: remainder := remainder/the_base;
61: end loop;
62: return res;
63: end Create;
64:
65: function Create ( n : natural ) return Natural_Number is
66:
67: res : Natural_Number := Create(Create(n));
68:
69: begin
70: return res;
71: end Create;
72:
73: function Create ( n : Array_of_Naturals ) return Natural_Number is
74:
75: res : Natural_Number;
76: res_rep : Natural_Number_Rep(n'last);
77:
78: begin
79: res_rep.numb := n;
80: res := new Natural_Number_Rep'(res_rep);
81: return res;
82: end Create;
83:
84: function Create ( n : Natural_Number ) return natural is
85:
86: res : natural;
87:
88: begin
89: if Empty(n)
90: then res := 0;
91: else res := Coefficient(n,Size(n));
92: for i in reverse 0..Size(n)-1 loop
93: res := res*the_base + Coefficient(n,i);
94: end loop;
95: end if;
96: return res;
97: end Create;
98:
99: -- SELECTORS :
100:
101: function Base return natural is
102: begin
103: return the_base;
104: end Base;
105:
106: function Exponent return natural is
107: begin
108: return expo;
109: end Exponent;
110:
111: function Empty ( n : Natural_Number ) return boolean is
112: begin
113: return ( n = null );
114: end Empty;
115:
116: function Size ( n : Natural_Number ) return natural is
117: begin
118: if n = null
119: then return 0;
120: else return n.size;
121: end if;
122: end Size;
123:
124: function Decimal_Places ( n : natural ) return natural is
125:
126: acc : natural := 1;
127:
128: begin
129: for i in 0..n loop
130: if n < acc
131: then return i;
132: else acc := acc*10;
133: end if;
134: end loop;
135: return n;
136: end Decimal_Places;
137:
138: function Decimal_Places ( n : Natural_Number ) return natural is
139:
140: res : natural := 0;
141:
142: begin
143: if not Empty(n)
144: then for i in reverse 0..Size(n) loop
145: if n.numb(i) /= 0
146: then res := Decimal_Places(n.numb(i)) + i*expo;
147: exit;
148: end if;
149: end loop;
150: end if;
151: return res;
152: end Decimal_Places;
153:
154: function Coefficient ( n : Natural_Number; i : natural ) return natural is
155: begin
156: if (n = null or else i > n.size)
157: then return 0;
158: else return n.numb(i);
159: end if;
160: end Coefficient;
161:
162: function Coefficients ( n : Natural_Number ) return Array_of_Naturals is
163:
164: na : Array_of_Naturals(0..0) := (0..0 => 0);
165:
166: begin
167: if Empty(n)
168: then return na;
169: else return n.numb;
170: end if;
171: end Coefficients;
172:
173: -- COMPARISON AND COPYING :
174: -- Note that these implementations are all independent of the
175: -- actual representation of Natural_Number as they use the selectors.
176:
177: function Equal ( n1,n2 : Array_of_Naturals ) return boolean is
178: begin
179: if n1'first /= n2'first
180: then return false;
181: elsif n1'last /= n2'last
182: then return false;
183: else for i in n1'range loop
184: if n1(i) /= n2(i)
185: then return false;
186: end if;
187: end loop;
188: return true;
189: end if;
190: end Equal;
191:
192: function Equal ( n1 : Natural_Number; n2 : natural ) return boolean is
193: begin
194: if Empty(n1)
195: then if n2 = 0
196: then return true;
197: else return false;
198: end if;
199: else declare
200: n2cff : constant Array_of_Naturals := Create(n2);
201: begin
202: if n2cff'last > Size(n1)
203: then return false;
204: else for i in n2cff'range loop
205: if Coefficient(n1,i) /= n2cff(i)
206: then return false;
207: end if;
208: end loop;
209: for i in n2cff'last+1..Size(n1) loop
210: if Coefficient(n1,i) /= 0
211: then return false;
212: end if;
213: end loop;
214: end if;
215: end;
216: return true;
217: end if;
218: end Equal;
219:
220: function Equal ( n1,n2 : Natural_Number ) return boolean is
221:
222: min_size : natural;
223:
224: begin
225: if Empty(n1)
226: then return Equal(n2,0);
227: else if Empty(n2)
228: then return Equal(n1,0);
229: else if Size(n1) < Size(n2)
230: then for i in Size(n1)+1..Size(n2) loop
231: if Coefficient(n2,i) /= 0
232: then return false;
233: end if;
234: end loop;
235: min_size := Size(n1);
236: elsif Size(n1) > Size(n2)
237: then for i in Size(n2)+1..Size(n1) loop
238: if Coefficient(n1,i) /= 0
239: then return false;
240: end if;
241: end loop;
242: min_size := Size(n2);
243: else min_size := Size(n1);
244: end if;
245: return Equal(Coefficients(n1)(0..min_size),
246: Coefficients(n2)(0..min_size));
247: end if;
248: end if;
249: end Equal;
250:
251: function "<" ( n1 : Natural_Number; n2 : natural ) return boolean is
252: begin
253: if Empty(n1)
254: then if n2 > 0
255: then return true;
256: else return false;
257: end if;
258: else declare
259: n2cff : constant Array_of_Naturals := Create(n2);
260: begin
261: if n2cff'last > Size(n1)
262: then return true;
263: else if n2cff'last < Size(n1)
264: then for i in reverse n2cff'last+1..Size(n1) loop
265: if Coefficient(n1,i) /= 0
266: then return false;
267: end if;
268: end loop;
269: end if;
270: for i in reverse n2cff'range loop
271: if Coefficient(n1,i) >= n2cff(i)
272: then return false;
273: end if;
274: end loop;
275: end if;
276: end;
277: return true;
278: end if;
279: end "<";
280:
281: function "<" ( n1 : natural; n2 : Natural_Number ) return boolean is
282: begin
283: if Empty(n2)
284: then return false;
285: else declare
286: n1cff : constant Array_of_Naturals := Create(n1);
287: begin
288: if n1cff'last > Size(n2)
289: then return false;
290: else if n1cff'last < Size(n2)
291: then for i in reverse n1cff'last+1..Size(n2) loop
292: if Coefficient(n2,i) /= 0
293: then return true;
294: end if;
295: end loop;
296: end if;
297: for i in reverse n1cff'range loop
298: if n1cff(i) >= Coefficient(n2,i)
299: then return false;
300: end if;
301: end loop;
302: end if;
303: end;
304: return true;
305: end if;
306: end "<";
307:
308: function "<" ( n1,n2 : Natural_Number ) return boolean is
309:
310: min_size : natural;
311:
312: begin
313: if Empty(n1)
314: then if Empty(n2)
315: then return false;
316: else return true;
317: end if;
318: else if Empty(n2)
319: then return false;
320: else if Size(n1) < Size(n2)
321: then for i in Size(n1)+1..Size(n2) loop
322: if Coefficient(n2,i) /= 0
323: then return true;
324: end if;
325: end loop;
326: min_size := Size(n1);
327: elsif Size(n1) > Size(n2)
328: then for i in Size(n2)+1..Size(n1) loop
329: if Coefficient(n1,i) /= 0
330: then return false;
331: end if;
332: end loop;
333: min_size := Size(n2);
334: else min_size := Size(n1);
335: end if;
336: for i in reverse 0..min_size loop
337: if Coefficient(n1,i) < Coefficient(n2,i)
338: then return true;
339: elsif Coefficient(n1,i) > Coefficient(n2,i)
340: then return false;
341: end if;
342: end loop;
343: return false; -- n1 = n2
344: end if;
345: end if;
346: end "<";
347:
348: function ">" ( n1 : Natural_Number; n2 : natural ) return boolean is
349: begin
350: if Empty(n1)
351: then return false;
352: else declare
353: n2cff : constant Array_of_Naturals := Create(n2);
354: begin
355: if n2cff'last > Size(n1)
356: then return false;
357: else if n2cff'last < Size(n1)
358: then for i in n2cff'last+1..Size(n1) loop
359: if Coefficient(n1,i) /= 0
360: then return true;
361: end if;
362: end loop;
363: end if;
364: for i in reverse n2cff'range loop
365: if Coefficient(n1,i) <= n2cff(i)
366: then return false;
367: end if;
368: end loop;
369: end if;
370: end;
371: return true;
372: end if;
373: end ">";
374:
375: function ">" ( n1 : natural; n2 : Natural_Number ) return boolean is
376: begin
377: if Empty(n2)
378: then if n1 > 0
379: then return true;
380: else return false;
381: end if;
382: else declare
383: n1cff : constant Array_of_Naturals := Create(n1);
384: begin
385: if n1cff'last > Size(n2)
386: then return true;
387: else if n1cff'last < Size(n2)
388: then for i in n1cff'last+1..Size(n2) loop
389: if Coefficient(n2,i) /= 0
390: then return false;
391: end if;
392: end loop;
393: end if;
394: for i in reverse n1cff'range loop
395: if n1cff(i) <= Coefficient(n2,i)
396: then return false;
397: end if;
398: end loop;
399: end if;
400: end;
401: return true;
402: end if;
403: end ">";
404:
405: function ">" ( n1,n2 : Natural_Number ) return boolean is
406:
407: min_size : natural;
408:
409: begin
410: if Empty(n2)
411: then if Empty(n1)
412: then return false;
413: else return true;
414: end if;
415: else if Empty(n1)
416: then return false;
417: else if Size(n1) < Size(n2)
418: then for i in Size(n1)+1..Size(n2) loop
419: if Coefficient(n2,i) /= 0
420: then return false;
421: end if;
422: end loop;
423: min_size := Size(n1);
424: elsif Size(n1) > Size(n2)
425: then for i in Size(n2)+1..Size(n1) loop
426: if Coefficient(n1,i) /= 0
427: then return true;
428: end if;
429: end loop;
430: min_size := Size(n2);
431: else min_size := Size(n1);
432: end if;
433: for i in reverse 0..min_size loop
434: if Coefficient(n1,i) > Coefficient(n2,i)
435: then return true;
436: elsif Coefficient(n1,i) < Coefficient(n2,i)
437: then return false;
438: end if;
439: end loop;
440: return false; -- n1 = n2
441: end if;
442: end if;
443: end ">";
444:
445: procedure Copy ( n1 : in natural; n2 : in out Natural_Number ) is
446: begin
447: Clear(n2);
448: n2 := Create(n1);
449: end Copy;
450:
451: procedure Copy ( n1 : in Natural_Number; n2 : in out Natural_Number ) is
452: begin
453: Clear(n2);
454: if not Empty(n1)
455: then declare
456: n2rep : Natural_Number_Rep(Size(n1));
457: begin
458: for i in n2rep.numb'range loop
459: n2rep.numb(i) := n1.numb(i);
460: end loop;
461: n2 := new Natural_Number_Rep'(n2rep);
462: end;
463: end if;
464: end Copy;
465:
466: -- AUXILIARIES FOR ARITHMETIC OPERATIONS :
467:
468: function Extend ( n : Array_of_Naturals; carry : natural )
469: return Natural_Number_Rep is
470:
471: -- DESCRIPTION :
472: -- Extends the array of naturals as much as need to store the carry
473: -- obtained from adding a number to a natural number.
474:
475: begin
476: if carry = 0
477: then declare
478: nrep : Natural_Number_Rep(n'last);
479: begin
480: nrep.numb := n;
481: return nrep;
482: end;
483: else declare
484: np1 : Array_of_Naturals(n'first..n'last+1);
485: carry1 : natural;
486: begin
487: np1(n'range) := n;
488: np1(np1'last) := carry mod the_base;
489: carry1 := carry/the_base;
490: return Extend(np1,carry1);
491: end;
492: end if;
493: end Extend;
494:
495: procedure Extend ( n : in out Natural_Number; carry : in natural ) is
496:
497: -- DESCRIPTION :
498: -- Extends the coefficient vector of the natural number to store
499: -- the carry-over.
500:
501: begin
502: if carry /= 0
503: then declare
504: res : Natural_Number
505: := new Natural_Number_Rep'(Extend(n.numb,carry));
506: begin
507: Clear(n);
508: n := res;
509: end;
510: end if;
511: end Extend;
512:
513: procedure Mul_Fact ( n : in out Natural_Number; f : in natural ) is
514:
515: -- DESCRIPTION :
516: -- Multiplies the number n with 0 < f <= fact and stores the result in n.
517:
518: prod,carry : natural;
519:
520: begin
521: if not Empty(n)
522: then carry := 0;
523: for i in n.numb'range loop
524: prod := n.numb(i)*f + carry;
525: n.numb(i) := prod mod the_base;
526: carry := prod/the_base;
527: end loop;
528: Extend(n,carry);
529: end if;
530: end Mul_Fact;
531:
532: procedure Mul_Base ( n : in out Natural_Number; k : in natural ) is
533:
534: -- DESCRIPTION :
535: -- Multiplies the number n with the_base**k.
536:
537: begin
538: if k > 0 and not Empty(n)
539: then declare
540: npk : Natural_Number_Rep(n.size+k);
541: begin
542: npk.numb(0..k-1) := (0..k-1 => 0);
543: npk.numb(k..npk.numb'last) := n.numb(n.numb'range);
544: Clear(n);
545: n := new Natural_Number_Rep'(npk);
546: end;
547: end if;
548: end Mul_Base;
549:
550: procedure Div_Base ( n : in out Natural_Number; k : in natural ) is
551:
552: -- DESCRIPTION :
553: -- Divides the number n by the_base**k.
554:
555: begin
556: if k > 0 and not Empty(n)
557: then if k > Size(n)
558: then Clear(n);
559: else declare
560: nmk : Natural_Number_Rep(n.size-k);
561: begin
562: for i in nmk.numb'range loop
563: nmk.numb(i) := n.numb(k+i);
564: end loop;
565: Clear(n);
566: n := new Natural_Number_Rep'(nmk);
567: end;
568: end if;
569: end if;
570: end Div_Base;
571:
572: -- ARITHMETIC OPERATIONS :
573:
574: function "+" ( n1 : Natural_Number; n2 : natural ) return Natural_Number is
575:
576: res : Natural_Number;
577:
578: begin
579: if Empty(n1)
580: then res := Create(n2);
581: else declare
582: cff : Array_of_Naturals(n1.numb'range);
583: sum,carry : natural;
584: begin
585: carry := n2;
586: for i in cff'range loop
587: sum := n1.numb(i) + carry;
588: cff(i) := sum mod the_base;
589: carry := sum/the_base;
590: end loop;
591: res := new Natural_Number_Rep'(Extend(cff,carry));
592: end;
593: end if;
594: return res;
595: end "+";
596:
597: function "+" ( n1 : natural; n2 : Natural_Number ) return Natural_Number is
598: begin
599: return n2+n1;
600: end "+";
601:
602: function "+" ( n1,n2 : Natural_Number ) return Natural_Number is
603:
604: res : Natural_Number;
605: sum,carry : natural;
606:
607: begin
608: if Empty(n1)
609: then Copy(n2,res);
610: elsif Empty(n2)
611: then Copy(n1,res);
612: else carry := 0;
613: if Size(n1) > Size(n2)
614: then declare
615: res_rep : Natural_Number_Rep(Size(n1)) := n1.all;
616: begin
617: for i in n2.numb'range loop
618: sum := res_rep.numb(i) + n2.numb(i) + carry;
619: res_rep.numb(i) := sum mod the_base;
620: carry := sum/the_base;
621: end loop;
622: if carry /= 0
623: then for i in n2.numb'last+1..n1.numb'last loop
624: sum := res_rep.numb(i) + carry;
625: res_rep.numb(i) := sum mod the_base;
626: carry := sum/the_base;
627: exit when (carry = 0);
628: end loop;
629: end if;
630: res := new Natural_Number_Rep'(res_rep);
631: end;
632: else declare
633: res_rep : Natural_Number_Rep(Size(n2)) := n2.all;
634: begin
635: for i in n1.numb'range loop
636: sum := res_rep.numb(i) + n1.numb(i) + carry;
637: res_rep.numb(i) := sum mod the_base;
638: carry := sum/the_base;
639: end loop;
640: if carry /= 0
641: then for i in n1.numb'last+1..n2.numb'last loop
642: sum := res_rep.numb(i) + carry;
643: res_rep.numb(i) := sum mod the_base;
644: carry := sum/the_base;
645: exit when (carry = 0);
646: end loop;
647: end if;
648: res := new Natural_Number_Rep'(res_rep);
649: end;
650: end if;
651: Extend(res,carry);
652: end if;
653: return res;
654: end "+";
655:
656: procedure Add ( n1 : in out Natural_Number; n2 : in natural ) is
657:
658: sum,carry : natural;
659:
660: begin
661: if Empty(n1)
662: then n1 := Create(n2);
663: else carry := n2;
664: for i in n1.numb'range loop
665: sum := n1.numb(i) + carry;
666: n1.numb(i) := sum mod the_base;
667: carry := sum/the_base;
668: end loop;
669: Extend(n1,carry);
670: end if;
671: end Add;
672:
673: procedure Add ( n1 : in out Natural_Number; n2 : in Natural_Number ) is
674:
675: res : Natural_Number;
676: sum,carry : natural;
677:
678: begin
679: if Empty(n1)
680: then Copy(n2,n1);
681: elsif not Empty(n2)
682: then carry := 0;
683: if Size(n1) >= Size(n2)
684: then for i in n2.numb'range loop
685: sum := n1.numb(i) + n2.numb(i) + carry;
686: n1.numb(i) := sum mod the_base;
687: carry := sum/the_base;
688: end loop;
689: if carry /= 0
690: then for i in n2.numb'last+1..n1.numb'last loop
691: sum := n1.numb(i) + carry;
692: n1.numb(i) := sum mod the_base;
693: carry := sum/the_base;
694: exit when (carry = 0);
695: end loop;
696: Extend(n1,carry);
697: end if;
698: else declare
699: res_rep : Natural_Number_Rep(Size(n2)) := n2.all;
700: begin
701: for i in n1.numb'range loop
702: sum := res_rep.numb(i) + n1.numb(i) + carry;
703: res_rep.numb(i) := sum mod the_base;
704: carry := sum/the_base;
705: end loop;
706: if carry /= 0
707: then for i in n1.numb'last+1..n2.numb'last loop
708: sum := res_rep.numb(i) + carry;
709: res_rep.numb(i) := sum mod the_base;
710: carry := sum/the_base;
711: exit when (carry = 0);
712: end loop;
713: end if;
714: Clear(n1);
715: n1 := new Natural_Number_Rep'(res_rep);
716: if carry /= 0
717: then Extend(n1,carry);
718: end if;
719: end;
720: end if;
721: end if;
722: end Add;
723:
724: function "-" ( n1 : Natural_Number; n2 : natural ) return Natural_Number is
725:
726: res : Natural_Number;
727: diff,carry : integer;
728:
729: begin
730: if not Empty(n1)
731: then Copy(n1,res);
732: declare
733: n2cff : constant Array_of_Naturals := Create(n2);
734: index : natural := n2cff'first;
735: begin
736: carry := n2cff(index);
737: for i in n1.numb'range loop
738: diff := n1.numb(i) - carry;
739: if diff >= 0
740: then res.numb(i) := diff mod the_base;
741: carry := diff/the_base;
742: else diff := the_base + diff;
743: res.numb(i) := diff mod the_base;
744: carry := diff/the_base + (res.numb(i)+carry)/the_base;
745: end if;
746: if index < n2cff'last
747: then index := index+1;
748: carry := carry + n2cff(index);
749: end if;
750: exit when (carry = 0);
751: end loop;
752: end;
753: end if;
754: return res;
755: end "-";
756:
757: function "-" ( n1 : natural; n2 : Natural_Number ) return Natural_Number is
758:
759: tmp : Natural_Number := Create(n1);
760: res : Natural_Number := tmp - n2;
761:
762: begin
763: Clear(tmp);
764: return res;
765: end "-";
766:
767: function "-" ( n1,n2 : Natural_Number ) return Natural_Number is
768:
769: res,diff : Natural_Number;
770:
771: begin
772: Copy(n1,res);
773: if not Empty(n2)
774: then for i in reverse n2.numb'range loop
775: Copy(res,diff);
776: Div_Base(diff,i);
777: if not Empty(diff)
778: then Sub(diff,n2.numb(i));
779: for j in diff.numb'range loop
780: res.numb(i+j) := diff.numb(j);
781: end loop;
782: Clear(diff);
783: end if;
784: end loop;
785: end if;
786: return res;
787: end "-";
788:
789: function "+" ( n : Natural_Number ) return Natural_Number is
790:
791: res : Natural_Number;
792:
793: begin
794: Copy(n,res);
795: return res;
796: end "+";
797:
798: function "-" ( n : Natural_Number ) return Natural_Number is
799:
800: res : Natural_Number;
801:
802: begin
803: Copy(n,res);
804: return res;
805: end "-";
806:
807: procedure Min ( n : in out Natural_Number ) is
808: begin
809: null;
810: end Min;
811:
812: procedure Sub ( n1 : in out Natural_Number; n2 : in natural ) is
813:
814: diff,carry : integer;
815:
816: begin
817: if not Empty(n1) and n2 > 0
818: then declare
819: n2cff : constant Array_of_Naturals := Create(n2);
820: index : natural := n2cff'first;
821: begin
822: carry := n2cff(index);
823: for i in n1.numb'range loop
824: diff := n1.numb(i) - carry;
825: if diff >= 0
826: then n1.numb(i) := diff mod the_base;
827: carry := diff/the_base;
828: else diff := the_base + diff;
829: n1.numb(i) := diff mod the_base;
830: carry := diff/the_base + (n1.numb(i)+carry)/the_base;
831: end if;
832: if index < n2cff'last
833: then index := index+1;
834: carry := carry + n2cff(index);
835: end if;
836: exit when (carry = 0);
837: end loop;
838: end;
839: end if;
840: end Sub;
841:
842: procedure Sub ( n1 : in out Natural_Number; n2 : in Natural_Number ) is
843:
844: res,diff : Natural_Number;
845:
846: begin
847: if not Empty(n1) and not Empty(n2)
848: then for i in reverse n2.numb'range loop
849: Copy(n1,diff);
850: Div_Base(diff,i);
851: if not Empty(diff)
852: then Sub(diff,n2.numb(i));
853: for j in diff.numb'range loop
854: n1.numb(i+j) := diff.numb(j);
855: end loop;
856: Clear(diff);
857: end if;
858: end loop;
859: end if;
860: end Sub;
861:
862: function "*" ( n1 : Natural_Number; n2 : natural ) return Natural_Number is
863:
864: res,prod,nres : Natural_Number;
865: remainder,modfact : natural;
866: cnt : natural := 0;
867:
868: begin
869: if n2 /= 0
870: then remainder := n2;
871: while remainder /= 0 loop
872: modfact := remainder mod fact;
873: if modfact /= 0
874: then Copy(n1,prod);
875: Mul_Fact(prod,modfact);
876: for i in 1..cnt loop
877: Mul_Fact(prod,fact);
878: end loop;
879: Add(res,prod);
880: Clear(prod);
881: end if;
882: cnt := cnt+1;
883: remainder := remainder/fact;
884: end loop;
885: end if;
886: return res;
887: end "*";
888:
889: function "*" ( n1 : natural; n2 : Natural_Number ) return Natural_Number is
890: begin
891: return n2*n1;
892: end "*";
893:
894: function "*" ( n1,n2 : Natural_Number ) return Natural_Number is
895:
896: res,prod : Natural_Number;
897:
898: begin
899: if (Empty(n1) or else Empty(n2))
900: then return res;
901: else if Size(n1) >= Size(n2)
902: then for i in n2.numb'range loop
903: prod := n1*n2.numb(i);
904: Mul_Base(prod,i);
905: Add(res,prod);
906: Clear(prod);
907: end loop;
908: else for i in n1.numb'range loop
909: prod := n2*n1.numb(i);
910: Mul_Base(prod,i);
911: Add(res,prod);
912: Clear(prod);
913: end loop;
914: end if;
915: end if;
916: return res;
917: end "*";
918:
919: procedure Mul ( n1 : in out Natural_Number; n2 : in natural ) is
920:
921: res,prod : Natural_Number;
922: remainder,modfact : natural;
923: cnt : natural := 0;
924:
925: begin
926: if n2 = 0
927: then Clear(n1);
928: else remainder := n2;
929: while remainder /= 0 loop
930: modfact := remainder mod fact;
931: if modfact /= 0
932: then Copy(n1,prod);
933: Mul_Fact(prod,modfact);
934: for i in 1..cnt loop
935: Mul_Fact(prod,fact);
936: end loop;
937: Add(res,prod);
938: Clear(prod);
939: end if;
940: cnt := cnt+1;
941: remainder := remainder/fact;
942: end loop;
943: Clear(n1);
944: n1 := res;
945: end if;
946: end Mul;
947:
948: procedure Mul ( n1 : in out Natural_Number; n2 : in Natural_Number ) is
949:
950: res,prod : Natural_Number;
951:
952: begin
953: if not Empty(n1)
954: then if Empty(n2)
955: then Clear(n1);
956: else if Size(n1) >= Size(n2)
957: then for i in n2.numb'range loop
958: prod := n1*n2.numb(i);
959: Mul_Base(prod,i);
960: Add(res,prod);
961: Clear(prod);
962: end loop;
963: else for i in n1.numb'range loop
964: prod := n2*n1.numb(i);
965: Mul_Base(prod,i);
966: Add(res,prod);
967: Clear(prod);
968: end loop;
969: end if;
970: Clear(n1);
971: n1 := res;
972: end if;
973: end if;
974: end Mul;
975:
976: function "**" ( n1 : Natural_Number; n2 : natural ) return Natural_Number is
977:
978: res : Natural_Number;
979:
980: begin
981: if n2 = 0
982: then res := Create(1);
983: else if not Empty(n1)
984: then Copy(n1,res);
985: for i in 1..n2-1 loop
986: Mul(res,n1);
987: end loop;
988: end if;
989: end if;
990: return res;
991: end "**";
992:
993: function "**" ( n1 : natural; n2 : Natural_Number ) return Natural_Number is
994:
995: res,cnt : Natural_Number;
996:
997: begin
998: if Equal(n2,0)
999: then res := Create(1);
1000: else res := Create(n1);
1001: if n1 /= 0
1002: then cnt := Create(1);
1003: while not Equal(cnt,n2) loop
1004: Mul(res,n1);
1005: Add(cnt,1);
1006: end loop;
1007: Clear(cnt);
1008: end if;
1009: end if;
1010: return res;
1011: end "**";
1012:
1013: function "**" ( n1,n2 : Natural_Number ) return Natural_Number is
1014:
1015: res,cnt : Natural_Number;
1016:
1017: begin
1018: if Equal(n2,0)
1019: then res := Create(1);
1020: else if not Empty(n1)
1021: then Copy(n1,res);
1022: cnt := Create(1);
1023: while not Equal(cnt,n2) loop
1024: Mul(res,n1);
1025: Add(cnt,1);
1026: end loop;
1027: Clear(cnt);
1028: end if;
1029: end if;
1030: return res;
1031: end "**";
1032:
1033: procedure Small_Div ( n1 : in Natural_Number; n2 : in natural;
1034: q : out Natural_Number; r : out natural ) is
1035:
1036: -- DESCRIPTION :
1037: -- n1 = n2*q + r, only applies when n2 <= fact.
1038:
1039: -- res : Natural_Number;
1040: carry : natural := 0;
1041:
1042: begin
1043: if n2 /= 0
1044: then if not Empty(n1)
1045: then -- res := new Natural_Number_Rep(Size(n1));
1046: q := new Natural_Number_Rep(Size(n1));
1047: for i in reverse 1..Size(n1) loop
1048: -- res.numb(i) := (n1.numb(i)+carry)/n2;
1049: q.numb(i) := (n1.numb(i)+carry)/n2;
1050: carry := (n1.numb(i)+carry) mod n2;
1051: carry := carry*the_base;
1052: end loop;
1053: -- res.numb(0) := (n1.numb(0)+carry)/n2;
1054: q.numb(0) := (n1.numb(0)+carry)/n2;
1055: carry := (n1.numb(0)+carry) mod n2;
1056: end if;
1057: else raise NUMERIC_ERROR;
1058: end if;
1059: -- q := res;
1060: r := carry;
1061: end Small_Div;
1062:
1063: procedure Small_Div ( n1 : in out Natural_Number; n2 : in natural;
1064: r : out natural ) is
1065:
1066: q : Natural_Number;
1067:
1068: begin
1069: Small_Div(n1,n2,q,r);
1070: Copy(q,n1); Clear(q);
1071: end Small_Div;
1072:
1073: procedure Big_Div ( n1 : in Natural_Number; n2 : in natural;
1074: q : out Natural_Number; r : out natural ) is
1075:
1076: -- DESCRIPTION :
1077: -- This division has to be applied when n2 > fact.
1078:
1079: wrkn1,shiftn1,remn1,acc,qres,qsub : Natural_Number;
1080: cntshf,cntsub,rres : natural;
1081:
1082: begin
1083: if n2 /= 0
1084: then
1085: if n1 < n2
1086: then
1087: q := qres;
1088: r := Create(n1);
1089: else
1090: Copy(n1,shiftn1); -- we have n1 >= n2
1091: Small_Div(shiftn1,fact,wrkn1,rres);
1092: cntshf := 0;
1093: while not (wrkn1 < n2) loop -- invariant n2 <= shiftn1
1094: acc := Create(rres);
1095: for i in 1..cntshf loop
1096: Mul_Fact(acc,fact);
1097: end loop;
1098: Add(remn1,acc); Clear(acc);
1099: Copy(wrkn1,shiftn1);
1100: cntshf := cntshf + 1;
1101: Small_Div(wrkn1,fact,rres); -- at end of loop
1102: end loop; -- shiftn1/fact < n2 <= shiftn1
1103: Clear(wrkn1);
1104: cntsub := 0;
1105: while not (shiftn1 < n2) loop -- subtract n2 from shiftn1
1106: cntsub := cntsub + 1;
1107: Sub(shiftn1,n2);
1108: end loop;
1109: qsub := Create(cntsub); -- intermediate quotient
1110: for i in 1..cntshf loop
1111: Mul_Fact(qsub,fact);
1112: Mul_Fact(shiftn1,fact);
1113: end loop;
1114: Add(shiftn1,remn1);
1115: Clear(remn1);
1116: Div(shiftn1,n2,qres,r); -- recursive call
1117: Add(qsub,qres); -- collect results
1118: q := qsub;
1119: Clear(qres); Clear(shiftn1); -- cleaning up
1120: end if;
1121: else
1122: raise NUMERIC_ERROR;
1123: end if;
1124: end Big_Div;
1125:
1126: function "/" ( n1 : Natural_Number; n2 : natural ) return Natural_Number is
1127:
1128: res : Natural_Number;
1129: r : natural;
1130:
1131: begin
1132: if not Empty(n1)
1133: then if n2 <= fact
1134: then Small_Div(n1,n2,res,r);
1135: else Big_Div(n1,n2,res,r);
1136: end if;
1137: end if;
1138: return res;
1139: end "/";
1140:
1141: function "/" ( n1 : natural; n2 : Natural_Number ) return natural is
1142:
1143: res : natural;
1144:
1145: begin
1146: if n1 < n2
1147: then res := 0;
1148: elsif not Empty(n2)
1149: then res := Create(n2);
1150: res := n1/res;
1151: else raise NUMERIC_ERROR;
1152: end if;
1153: return res;
1154: end "/";
1155:
1156: function "/" ( n1,n2 : Natural_Number ) return Natural_Number is
1157:
1158: res,rrr : Natural_Number;
1159:
1160: begin
1161: Div(n1,n2,res,rrr);
1162: Clear(rrr);
1163: return res;
1164: end "/";
1165:
1166: function Rmd ( n1 : Natural_Number; n2 : natural ) return natural is
1167:
1168: res : natural;
1169: q : Natural_Number;
1170:
1171: begin
1172: if n2 <= fact
1173: then Small_Div(n1,n2,q,res);
1174: else Big_Div(n1,n2,q,res);
1175: end if;
1176: Clear(q);
1177: return res;
1178: end Rmd;
1179:
1180: function Rmd ( n1 : natural; n2 : Natural_Number ) return natural is
1181:
1182: res : natural;
1183:
1184: begin
1185: if n1 < n2
1186: then res := n1;
1187: elsif not Empty(n2)
1188: then res := Create(n2);
1189: res := n1 mod res;
1190: else raise NUMERIC_ERROR;
1191: end if;
1192: return res;
1193: end Rmd;
1194:
1195: function Rmd ( n1,n2 : Natural_Number ) return Natural_Number is
1196:
1197: res,q : Natural_Number;
1198:
1199: begin
1200: Div(n1,n2,q,res);
1201: Clear(q);
1202: return res;
1203: end Rmd;
1204:
1205: procedure Div ( n1 : in out Natural_Number; n2 : in natural ) is
1206:
1207: r : natural;
1208:
1209: begin
1210: Div(n1,n2,r);
1211: end Div;
1212:
1213: procedure Div ( n1 : in out Natural_Number; n2 : in Natural_Number ) is
1214:
1215: r : Natural_Number;
1216:
1217: begin
1218: Div(n1,n2,r);
1219: Clear(r);
1220: end Div;
1221:
1222: procedure Div ( n1 : in Natural_Number; n2 : in natural;
1223: q : out Natural_Number; r : out natural ) is
1224: begin
1225: if n2 <= fact
1226: then Small_Div(n1,n2,q,r);
1227: else Big_Div(n1,n2,q,r);
1228: end if;
1229: end Div;
1230:
1231: procedure Div ( n1 : in out Natural_Number; n2 : in natural;
1232: r : out natural ) is
1233:
1234: q : Natural_Number;
1235:
1236: begin
1237: Div(n1,n2,q,r);
1238: Copy(q,n1); Clear(q);
1239: end Div;
1240:
1241: procedure Div ( n1,n2 : in Natural_Number;
1242: q : out Natural_Number; r : out Natural_Number ) is
1243:
1244: wrkn1,shiftn1,remn1,acc,qres,qsub : Natural_Number;
1245: cntshf,cntsub,rres : natural;
1246:
1247: begin
1248: if (Empty(n2) or else Equal(n2,0))
1249: then
1250: raise NUMERIC_ERROR;
1251: else
1252: if n1 < n2
1253: then
1254: q := qres;
1255: Copy(n1,r);
1256: else
1257: Copy(n1,shiftn1); -- we have n1 >= n2
1258: Small_Div(shiftn1,fact,wrkn1,rres);
1259: cntshf := 0;
1260: while not (wrkn1 < n2) loop -- invariant n2 <= shiftn1
1261: acc := Create(rres);
1262: for i in 1..cntshf loop
1263: Mul_Fact(acc,fact);
1264: end loop;
1265: Add(remn1,acc); Clear(acc);
1266: Copy(wrkn1,shiftn1);
1267: cntshf := cntshf + 1;
1268: Small_Div(wrkn1,fact,rres); -- at end of loop
1269: end loop; -- shiftn1/fact < n2 <= shiftn1
1270: Clear(wrkn1);
1271: cntsub := 0;
1272: while not (shiftn1 < n2) loop -- subtract n2 from shiftn1
1273: cntsub := cntsub + 1;
1274: Sub(shiftn1,n2);
1275: end loop;
1276: qsub := Create(cntsub); -- intermediate quotient
1277: for i in 1..cntshf loop
1278: Mul_Fact(qsub,fact);
1279: Mul_Fact(shiftn1,fact);
1280: end loop;
1281: Add(shiftn1,remn1);
1282: Clear(remn1);
1283: Div(shiftn1,n2,qres,r); -- recursive call
1284: Add(qsub,qres); -- collect results
1285: q := qsub;
1286: Clear(qres); Clear(shiftn1); -- cleaning up
1287: end if;
1288: end if;
1289: end Div;
1290:
1291: procedure Div ( n1 : in out Natural_Number; n2 : in Natural_Number;
1292: r : out Natural_Number ) is
1293:
1294: q : Natural_Number;
1295:
1296: begin
1297: Div(n1,n2,q,r);
1298: Copy(q,n1); Clear(q);
1299: end Div;
1300:
1301: -- DESTRUCTOR :
1302:
1303: procedure Clear ( n : in out Natural_Number ) is
1304:
1305: procedure free is
1306: new unchecked_deallocation(Natural_Number_Rep,Natural_Number);
1307:
1308: begin
1309: if not Empty(n)
1310: then free(n);
1311: end if;
1312: end Clear;
1313:
1314: end Multprec_Natural_Numbers;
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>