Develop and Download Open Source Software

Browse CVS Repository

Contents of /netruby/netruby/Bignum.cs

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1.1.1 - (show annotations) (download) (vendor branch)
Mon Apr 8 13:27:10 2002 UTC (22 years ago) by arton
Branch: MAIN, vendor
CVS Tags: start, HEAD
Changes since 1.1: +0 -0 lines
initial version 0.8

1 /**********************************************************************
2
3 bignum.c -
4
5 $Author: matz $
6 $Date: 2001/11/01 05:09:51 $
7 created at: Fri Jun 10 00:48:55 JST 1994
8
9 Copyright (C) 1993-2000 Yukihiro Matsumoto
10
11 **********************************************************************/
12 /*
13 Copyright(C) 2001-2002 arton
14
15 Permission is granted for use, copying, modification, distribution,
16 and distribution of modified versions of this work as long as the
17 above copyright notice is included.
18 */
19
20 using System;
21 using System.Collections;
22 using System.Reflection;
23 using System.Security;
24 using System.Text;
25
26 namespace arton.NETRuby
27 {
28 public class RBignum : RInteger, IComparable, ICloneable
29 {
30
31 internal RBignum(NetRuby rb, int ln, bool sgn)
32 : base(rb, rb.cBignum)
33 {
34 sign = sgn;
35 len = ln;
36 digits = new uint[ln];
37 for (int i = 0; i < ln; i++) digits[i] = 0;
38 }
39
40 internal RBignum(NetRuby rb, uint u, bool sgn)
41 : base(rb, rb.cBignum)
42 {
43 sign = sgn;
44 len = 1;
45 digits = new uint[1];
46 digits[0] = u;
47 }
48
49 internal RBignum(NetRuby rb, long l)
50 : base(rb, rb.cBignum)
51 {
52 sign = (l < 0) ? false : true;
53 len = 2;
54 digits = new uint[2];
55 digits[0] = BIGLO(l);
56 digits[1] = (uint)BIGDN(l);
57 }
58
59 internal RBignum(NetRuby rb, uint[] us, bool sgn)
60 : base(rb, rb.cBignum)
61 {
62 sign = sgn;
63
64 len = us.Length;
65 digits = us;
66 // normalize
67 int i = len;
68 while (i-- != 0 && digits[i] == 0);
69 len = ++i;
70 }
71
72 private bool sign;
73 private int len;
74 private uint[] digits;
75
76 public ulong Big2Ulong()
77 {
78 if (len > 8)
79 throw new eRangeError("bignum too big to convert into `ulong'");
80 ulong num = 0;
81 int i = len;
82 while (i-- > 0)
83 {
84 num = BIGUP(num);
85 num += digits[i];
86 }
87 return num;
88 }
89
90 public override RFloat ToFloat()
91 {
92 return new RFloat(ruby, Big2Dbl());
93 }
94
95 public override long ToLong()
96 {
97 ulong num = Big2Ulong();
98 if (num > (ulong)Int64.MaxValue)
99 throw new eRangeError("bignum too big to convert into `long'");
100 long l = (long)num;
101 return (sign) ? l : -l;
102 }
103
104 public override object Clone()
105 {
106 RBignum big = new RBignum(ruby, len, sign);
107 Array.Copy(digits, big.digits, len);
108 return big;
109 }
110
111 public void TwoComp()
112 {
113 int i = len;
114 while (i-- > 0) digits[i] = ~digits[i];
115 i = 0;
116 ulong num = 1;
117 do
118 {
119 num += digits[i];
120 digits[i++] = BIGLO(num);
121 num = BIGDN(num);
122 }
123 while (i < len);
124 if (digits[0] == 1 || digits[0] == 0)
125 {
126 for (i = 1; i < len; i++)
127 {
128 if (digits[i] != 0) return;
129 }
130 uint[] ns = new uint[len + 1];
131 for (i = 0; i < len; i++)
132 ns[i] = digits[i];
133 ns[len] = 1;
134 len++;
135 digits = ns;
136 }
137 }
138 public double Big2Dbl()
139 {
140 double d = 0.0;
141 int i = len;
142 while (i-- != 0)
143 {
144 d = digits[i] + BIGRAD * d;
145 }
146 return (sign) ? d : -d;
147 }
148
149 public static RBignum Dbl2Big(NetRuby ruby, double d)
150 {
151 if (Double.IsInfinity(d))
152 {
153 throw new eFloatDomainError((d < 0) ? "-Infinity" : "Infinity");
154 }
155 if (Double.IsNaN(d))
156 {
157 throw new eFloatDomainError("NaN");
158 }
159 int i = 0;
160 double u = (d < 0) ? -d : d;
161 while (u <= Int32.MaxValue == false || 0 != (int)u)
162 {
163 u /= (double)BIGRAD;
164 i++;
165 }
166 uint[] dg = new uint[i];
167 while (i-- != 0)
168 {
169 u *= BIGRAD;
170 dg[i] = (uint)u;
171 u -= dg[i];
172 }
173 return new RBignum(ruby, dg, (d >= 0));
174 }
175
176 public static RBignum Int2Big(NetRuby ruby, int n)
177 {
178 bool neg = false;
179 if (n < 0)
180 {
181 n = -n;
182 neg = true;
183 }
184 RBignum big = Uint2Big(ruby, (uint)n);
185 if (neg)
186 {
187 big.sign = false;
188 }
189 return big;
190 }
191
192 public static RBignum Uint2Big(NetRuby ruby, uint n)
193 {
194 RBignum big = new RBignum(ruby, 1, true);
195 big.digits[0] = n;
196 if (n == 0) big.len = 0;
197 return big;
198 }
199
200 public static RBignum Long2Big(NetRuby ruby, long n)
201 {
202 bool neg = false;
203 if (n < 0)
204 {
205 n = -n;
206 neg = true;
207 }
208 RBignum big = Ulong2Big(ruby, (ulong)n);
209 if (neg)
210 {
211 big.sign = false;
212 }
213 return big;
214 }
215
216 public static RBignum Ulong2Big(NetRuby ruby, ulong n)
217 {
218 ulong num = (ulong)n;
219 RBignum big = new RBignum(ruby, 2, true);
220 big.digits[0] = (uint)n;
221 big.digits[1] = (uint)(n >> 32);
222 return big;
223 }
224
225 static private RBignum to_big(NetRuby ruby, object o)
226 {
227 RBignum y = null;
228 if (o is RFixnum)
229 o = ((RFixnum)o).GetData();
230 if (o is RBignum)
231 y = (RBignum)o;
232 if (o is int)
233 y = Int2Big(ruby, (int)o);
234 else if (o is long)
235 y = Long2Big(ruby, (long)o);
236 else if (o is double)
237 y = Dbl2Big(ruby, (double)o);
238 else if (o is RFloat)
239 y = Dbl2Big(ruby, ((RFloat)o).Double);
240 return y;
241 }
242
243 public bool Eq(object o)
244 {
245 RBignum y = null;
246 if (o is RFixnum)
247 o = ((RFixnum)o).GetData();
248 if (o is int)
249 y = Int2Big(ruby, (int)o);
250 else if (o is long)
251 y = Long2Big(ruby, (long)o);
252 else if (o is double)
253 return (Big2Dbl() == (double)o);
254 else if (o is RFloat)
255 return (Big2Dbl() == ((RFloat)o).Double);
256 else if (o is RBignum == false)
257 return false;
258 else
259 y = (RBignum)o;
260 if (sign != y.sign) return false;
261 if (len != y.len) return false;
262 for (int i = 0; i < len; i++)
263 {
264 if (digits[i] != y.digits[i]) return false;
265 }
266 return true;
267 }
268
269 public override string ToString()
270 {
271 return ToRString(10).ToString();
272 }
273
274 public override RString ToRString()
275 {
276 return ToRString(10);
277 }
278 public override RInteger ToInteger()
279 {
280 return this;
281 }
282
283 private static readonly string hexmap = "0123456789abcdef";
284 public RString ToRString(int radix)
285 {
286 if (len == 0) return new RString(ruby, "0");
287 int j = 0;
288 int hbase = 0;
289 switch (radix)
290 {
291 case 10:
292 j = (32 * len * 241)/800 + 2;
293 hbase = 10000;
294 break;
295 case 16:
296 j = (32 * len) / 4 + 2;
297 hbase = 0x10000;
298 break;
299 case 8:
300 j = (32 * len) + 2;
301 hbase = 0x1000;
302 break;
303 case 2:
304 j = (32 * len) + 2;
305 hbase = 0x10;
306 break;
307 default:
308 throw new eArgError("bignum cannot treat base " + base.ToString());
309 }
310 uint[] t = new uint[len];
311 Array.Copy(digits, t, len);
312 StringBuilder ss = new StringBuilder(j);
313 ss.Length = j;
314 int i = len;
315 while (i != 0 && j != 0)
316 {
317 int k = i;
318 ulong num = 0;
319 while (k-- != 0)
320 {
321 num = BIGUP(num) + t[k];
322 t[k] = (uint)(num / (uint)hbase);
323 num %= (uint)hbase;
324 }
325 if (t[i - 1] == 0) i--;
326 k = 4;
327 while (k-- != 0)
328 {
329 int c = (char)(num % (uint)radix);
330 ss[--j] = hexmap[c];
331 num /= (uint)radix;
332 if (i == 0 && num == 0) break;
333 }
334 }
335 while (ss[j] == '0') j++;
336 if (sign == false)
337 {
338 ss[--j] = '-';
339 }
340 int ln = ss.Length - j;
341 string s = ss.ToString().Substring(j, ln);
342 return new RString(ruby, s);
343 }
344
345 public int CompareTo(object o)
346 {
347 RBignum r = to_big(ruby, o);
348 if (r == null)
349 {
350 throw new ArgumentException("object is not a Bignum");
351 }
352 if (sign && !r.sign) return 1;
353 if (!sign && r.sign) return -1;
354 if (len < r.len)
355 return (sign) ? -1 : 1;
356 if (len > r.len)
357 return (sign) ? 1 : -1;
358 int xlen = len;
359 while ((xlen-- > 0) && digits[xlen] == r.digits[xlen]);
360 if (xlen < 0) return 0;
361 return (digits[xlen] > r.digits[xlen]) ? (sign ? 1 : -1) : (sign ? -1 : 1);
362 }
363 public override bool Gt(object o)
364 {
365 RBignum r = to_big(ruby, o);
366 if (r == null)
367 {
368 return (bool)CoerceBin(o);
369 }
370 int i = CompareTo(r);
371 return i > 0;
372 }
373 public override bool GE(object o)
374 {
375 RBignum r = to_big(ruby, o);
376 if (r == null)
377 {
378 return (bool)CoerceBin(o);
379 }
380 int i = CompareTo(r);
381 return i >= 0;
382 }
383 public override bool Lt(object o)
384 {
385 RBignum r = to_big(ruby, o);
386 if (r == null)
387 {
388 return (bool)CoerceBin(o);
389 }
390 int i = CompareTo(r);
391 return i < 0;
392 }
393 public override bool LE(object o)
394 {
395 RBignum r = to_big(ruby, o);
396 if (r == null)
397 {
398 return (bool)CoerceBin(o);
399 }
400 int i = CompareTo(r);
401 return i <= 0;
402 }
403
404 public RInteger Negate()
405 {
406 RBignum z = (RBignum)Clone();
407 if (sign == false) z.TwoComp();
408 for (int i = 0; i < len; i++)
409 {
410 z.digits[i] = ~z.digits[i];
411 }
412 if (sign) z.TwoComp();
413 z.sign = !z.sign;
414 return z.Normalize;
415 }
416 public override RInteger Normalize
417 {
418 get {
419 int i = len;
420 while (i-- != 0 && digits[i] == 0);
421 len = ++i;
422 if (len <= 1 && (int)digits[0] <= Int32.MaxValue)
423 {
424 return new RFixnum(ruby, (sign ? (int)digits[0] : -(int)digits[0]));
425 }
426 return this;
427 }
428 }
429 public override RArray Coerce(object y)
430 {
431 if (y is int || y is long || y is RFixnum)
432 return RArray.AssocNew(ruby, to_big(ruby, y), this);
433 throw new eTypeError("Can't create " + ruby.ClassOf(y).Name + " to Bignum");
434 }
435 public override RNumeric Plus(object o)
436 {
437 return (this + to_big(ruby, o)).Normalize;
438 }
439 public override RNumeric Minus(object o)
440 {
441 return (this - to_big(ruby, o)).Normalize;
442 }
443 public override RNumeric Multiply(object o)
444 {
445 return (this * to_big(ruby, o)).Normalize;
446 }
447 public override RNumeric Divide(object o)
448 {
449 RBignum z;
450 RBignum y = divmod(o, out z);
451 return y.Normalize;
452 }
453 public override RNumeric Modulo(object o)
454 {
455 RBignum z;
456 divmod(o, out z);
457 return z.Normalize;
458 }
459 public override RNumeric Remainder(object o)
460 {
461 return (this % to_big(ruby, o)).Normalize;
462 }
463 public override RArray DivMod(object o)
464 {
465 RBignum z;
466 RBignum y = divmod(o, out z);
467 return RArray.AssocNew(ruby, y.Normalize, z.Normalize);
468 }
469 private RBignum divmod(object o, out RBignum mod)
470 {
471 mod = null;
472 RBignum y = to_big(ruby, o);
473 RBignum dv = divrem(y, out mod);
474 if (sign != y.sign && mod.len > 0)
475 {
476 dv = dv - to_big(ruby, 1);
477 mod = mod + y;
478 }
479 return dv;
480 }
481
482 public override bool Equals(object o)
483 {
484 return base.Equals(o);
485 }
486 public bool Sign
487 {
488 get { return sign; }
489 }
490 static internal object ruby_neg(RBasic r, params object[] args)
491 {
492 return ((RBignum)r).Negate();
493 }
494 static internal object ruby_eq(RBasic r, params object[] args)
495 {
496 return ((RBignum)r).Eq(args[0]);
497 }
498 public override int GetHashCode()
499 {
500 return base.GetHashCode();
501 }
502 public static bool operator ==(RBignum b1, RBignum b2)
503 {
504 return b1.Eq(b2);
505 }
506 public static bool operator !=(RBignum b1, RBignum b2)
507 {
508 return !b1.Eq(b2);
509 }
510 public static RBignum operator +(RBignum b1, RBignum b2)
511 {
512 return b1.add(b2, true);
513 }
514 public static RBignum operator -(RBignum b1, RBignum b2)
515 {
516 return b1.add(b2, false);
517 }
518 public static RBignum operator *(RBignum x, RBignum y)
519 {
520 int j = x.len + y.len + 1;
521 uint[] z = new uint[j];
522 while (j-- != 0) z[j] = 0;
523 for (int i = 0; i < x.len; i++)
524 {
525 ulong dd = x.digits[i];
526 if (dd == 0) continue;
527 ulong n = 0;
528 for (j = 0; j < y.len; j++)
529 {
530 ulong ee = n + dd * y.digits[j];
531 n = (ulong)z[i + j] + ee;
532 if (ee != 0) z[i + j] = BIGLO(n);
533 n = BIGDN(n);
534 }
535 if (n != 0)
536 {
537 z[i + j] = (uint)n;
538 }
539 }
540 return new RBignum(x.ruby, z, x.sign == y.sign);
541 }
542 public static RBignum operator /(RBignum x, RBignum y)
543 {
544 RBignum mod;
545 return x.divrem(y, out mod);
546 }
547 public static RBignum operator %(RBignum x, RBignum y)
548 {
549 RBignum mod;
550 RBignum div = x.divrem(y, out mod);
551 return mod;
552 }
553 public static bool operator >(RBignum x, RBignum y)
554 {
555 return x.Gt(y);
556 }
557 public static bool operator >=(RBignum x, RBignum y)
558 {
559 return x.GE(y);
560 }
561 public static bool operator <(RBignum x, RBignum y)
562 {
563 return x.Lt(y);
564 }
565 public static bool operator <=(RBignum x, RBignum y)
566 {
567 return x.LE(y);
568 }
569
570 private RBignum sub(RBignum y)
571 {
572 uint[] xx = digits;
573 uint[] yy = y.digits;
574 int xlen = len;
575 int ylen = y.len;
576 bool sig = true;
577 int i;
578 if (len < y.len)
579 {
580 xx = y.digits;
581 yy = digits;
582 sig = false;
583 xlen = y.len;
584 ylen = len;
585 }
586 else if (len == y.len)
587 {
588 for (i = len; i > 0; )
589 {
590 i--;
591 if (xx[i] > yy[i])
592 break;
593 if (xx[i] < yy[i])
594 {
595 xx = y.digits;
596 yy = digits;
597 xlen = y.len;
598 ylen = len;
599 sig = false;
600 }
601 }
602 }
603 uint[] z = new uint[xlen];
604 long num = 0;
605 for (i = 0; i < ylen; i++)
606 {
607 num += (long)xx[i] - yy[i];
608 z[i] = BIGLO(num);
609 num = BIGDN(num);
610 }
611 while (num != 0 && i < xlen)
612 {
613 num += xx[i];
614 z[i++] = BIGLO(num);
615 num = BIGDN(num);
616 }
617 while (i < xlen)
618 {
619 z[i] = xx[i];
620 i++;
621 }
622 return new RBignum(ruby, z, sig);
623 }
624 private RBignum add(RBignum y, bool s)
625 {
626 bool sig = (s == y.sign);
627 if (sign != sig)
628 {
629 if (sig) return y.sub(this);
630 return sub(y);
631 }
632 uint[] xx = digits;
633 uint[] yy = y.digits;
634 int xlen = len;
635 int ylen = y.len;
636 int nl = len;
637 if (nl > y.len)
638 {
639 nl++;
640 xx = y.digits;
641 yy = digits;
642 xlen = y.len;
643 ylen = len;
644 }
645 else
646 {
647 nl = y.len + 1;
648 }
649 uint[] z = new uint[nl];
650 ulong num = 0;
651 int i;
652 for (i = 0; i < xlen; i++)
653 {
654 num += (ulong)xx[i] + (ulong)yy[i];
655 z[i] = BIGLO(num);
656 num = BIGDN(num);
657 }
658 while (num != 0 && i < ylen)
659 {
660 num += yy[i];
661 z[i++] = BIGLO(num);
662 num = BIGDN(num);
663 }
664 while (i < ylen)
665 {
666 z[i] = yy[i];
667 i++;
668 }
669 z[i] = (uint)num;
670 return new RBignum(ruby, z, sig);
671 }
672
673 private RBignum divrem(RBignum y, out RBignum mod)
674 {
675 mod = null;
676 uint dd;
677 int ny = y.len;
678 int nx = len;
679 int i;
680 ulong t2;
681 if (ny == 0 && y.digits[0] == 0)
682 throw new DivideByZeroException("divided by 0");
683 if (nx < ny || nx == ny && digits[nx - 1] < y.digits[ny - 1])
684 {
685 mod = this;
686 return new RBignum(ruby, (uint)0, true);
687 }
688 if (ny == 1)
689 {
690 dd = y.digits[0];
691 RBignum z = (RBignum)Clone();
692 i = nx;
693 t2 = 0;
694 while (i-- != 0)
695 {
696 t2 = (ulong)BIGUP(t2) + z.digits[i];
697 z.digits[i] = (uint)(t2 / dd);
698 t2 %= dd;
699 }
700 z.sign = (sign == y.sign);
701 mod = Uint2Big(ruby, (uint)t2);
702 mod.sign = sign;
703 return z;
704 }
705
706 uint[] zz = new uint[(nx == ny) ? nx + 2 : nx + 1];
707 if (nx == ny) zz[nx + 1] = 0;
708 while (y.digits[ny - 1] == 0) ny--;
709
710 dd = 0;
711 uint q = y.digits[ny - 1];
712 int j = 0;
713 uint[] ys = y.digits;
714 while ((q & ((uint)1 << (int)(BITSPERDIG-1))) == 0)
715 {
716 q <<= 1;
717 dd++;
718 }
719 if (dd != 0)
720 {
721 RBignum yy = (RBignum)y.Clone();
722 j = 0;
723 t2 = 0;
724 while (j < ny)
725 {
726 t2 += ((ulong)y.digits[j]) << (int)dd;
727 yy.digits[j++] = BIGLO(t2);
728 t2 = BIGDN(t2);
729 }
730 ys = yy.digits;
731 j = 0;
732 t2 = 0;
733 while (j < nx)
734 {
735 t2 += ((ulong)digits[j]) << (int)dd;
736 zz[j++] = BIGLO(t2);
737 t2 = BIGDN(t2);
738 }
739 zz[j] = (uint)t2;
740 }
741 else
742 {
743 zz[nx] = 0;
744 j = nx;
745 while (j-- != 0) zz[j] = digits[j];
746 }
747
748 j = (nx == ny) ? nx + 1 : nx;
749 do
750 {
751 if (zz[j] == ys[ny - 1]) q = (uint)(BIGRAD - 1);
752 else q = (uint)((BIGUP(zz[j]) + zz[j - 1])/ys[ny - 1]);
753 if (q != 0)
754 {
755 i = 0;
756 long num = 0;
757 t2 = 0;
758 do
759 {
760 t2 += (ulong)ys[i] * q;
761 ulong ee = (ulong)(num - BIGLO(t2));
762 num = (long)(zz[j - ny + i] + ee);
763 if (ee != 0) zz[j - ny + i] = BIGLO(num);
764 num = BIGDN(num);
765 t2 = BIGDN(t2);
766 }
767 while (++i < ny);
768 num += (long)(zz[j - ny + i] - t2);
769 while (num != 0)
770 {
771 i = 0;
772 num = 0;
773 q--;
774 do
775 {
776 ulong ee = (ulong)(num + ys[i]);
777 num = (long)((ulong)zz[j - ny + i] + ee);
778 if (ee != 0) zz[j - ny + i] = BIGLO(num);
779 num = BIGDN(num);
780 }
781 while (++i < ny);
782 num--;
783 }
784 }
785 zz[j] = q;
786 }
787 while (--j >= ny);
788 RBignum div = new RBignum(ruby, zz, sign == y.sign);
789 mod = (RBignum)div.Clone();
790 j = (nx == ny ? nx + 2 : nx + 1) - ny;
791 for (i = 0; i < j; i++) div.digits[i] = div.digits[i + ny];
792 div.len = i;
793
794 while (ny-- != 0 && mod.digits[ny] == 0);
795 ny++;
796 if (dd != 0)
797 {
798 t2 = 0;
799 i = ny;
800 while (i-- != 0)
801 {
802 t2 = (t2 | mod.digits[i]) >> (int)dd;
803 q = mod.digits[i];
804 mod.digits[i] = BIGLO(t2);
805 t2 = BIGUP(q);
806 }
807 mod.len = ny;
808 mod.sign = sign;
809 }
810 return div;
811 }
812
813 static internal new void Init(NetRuby rb)
814 {
815 RClass big = rb.DefineClass("Bignum", rb.cInteger);
816 rb.cBignum = big;
817
818 big.DefineMethod("~", new RMethod(ruby_neg), 0);
819
820 RMethod rm = new RMethod(ruby_eq);
821 big.DefineMethod("==", rm, 1);
822 big.DefineMethod("===", rm, 1);
823 big.DefineMethod("eql?", rm, 1);
824 }
825 }
826 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26