bignum.c
DEFINITIONS
This source file includes following functions.
- bignew_1
- rb_big_clone
- get2comp
- rb_big_2comp
- bignorm
- rb_big_norm
- rb_uint2big
- rb_int2big
- rb_uint2inum
- rb_int2inum
- rb_quad_pack
- rb_quad_unpack
- rb_quad_pack
- rb_quad_unpack
- rb_cstr_to_inum
- rb_str_to_inum
- rb_ull2big
- rb_ll2big
- rb_ull2inum
- rb_ll2inum
- rb_cstr2inum
- rb_str2inum
- rb_big2str
- rb_big_to_s
- big2ulong
- rb_big2ulong
- rb_big2long
- big2ull
- rb_big2ull
- rb_big2ll
- dbl2big
- rb_dbl2big
- rb_big2dbl
- rb_big_to_f
- rb_big_cmp
- rb_big_eq
- rb_big_eql
- rb_big_uminus
- rb_big_neg
- bigsub
- bigadd
- rb_big_plus
- rb_big_minus
- rb_big_mul
- bigdivrem
- bigdivmod
- rb_big_div
- rb_big_modulo
- rb_big_remainder
- rb_big_divmod
- rb_big_pow
- rb_big_and
- rb_big_or
- rb_big_xor
- rb_big_lshift
- rb_big_rshift
- rb_big_aref
- rb_big_hash
- rb_big_coerce
- rb_big_abs
- rb_big_rand
- rb_big_size
- Init_Bignum
1
2
3
4
5
6
7
8
9
10
11
12
13 #include "ruby.h"
14
15 #include <math.h>
16 #include <ctype.h>
17
18 VALUE rb_cBignum;
19
20 #if defined __MINGW32__
21 #define USHORT _USHORT
22 #endif
23
24 #define BDIGITS(x) ((BDIGIT*)RBIGNUM(x)->digits)
25 #define BITSPERDIG (SIZEOF_BDIGITS*CHAR_BIT)
26 #define BIGRAD ((BDIGIT_DBL)1 << BITSPERDIG)
27 #define DIGSPERLONG ((unsigned int)(SIZEOF_LONG/SIZEOF_BDIGITS))
28 #if HAVE_LONG_LONG
29 # define DIGSPERLL ((unsigned int)(SIZEOF_LONG_LONG/SIZEOF_BDIGITS))
30 #endif
31 #define BIGUP(x) ((BDIGIT_DBL)(x) << BITSPERDIG)
32 #define BIGDN(x) RSHIFT(x,BITSPERDIG)
33 #define BIGLO(x) ((BDIGIT)((x) & (BIGRAD-1)))
34
35 static VALUE
36 bignew_1(klass, len, sign)
37 VALUE klass;
38 long len;
39 char sign;
40 {
41 NEWOBJ(big, struct RBignum);
42 OBJSETUP(big, klass, T_BIGNUM);
43 big->sign = sign;
44 big->len = len;
45 big->digits = ALLOC_N(BDIGIT, len);
46
47 return (VALUE)big;
48 }
49
50 #define bignew(len,sign) bignew_1(rb_cBignum,len,sign)
51
52 VALUE
53 rb_big_clone(x)
54 VALUE x;
55 {
56 VALUE z = bignew_1(CLASS_OF(x), RBIGNUM(x)->len, RBIGNUM(x)->sign);
57
58 MEMCPY(BDIGITS(z), BDIGITS(x), BDIGIT, RBIGNUM(x)->len);
59 return z;
60 }
61
62 static void
63 get2comp(x, carry)
64 VALUE x;
65 int carry;
66 {
67 long i = RBIGNUM(x)->len;
68 BDIGIT *ds = BDIGITS(x);
69 BDIGIT_DBL num;
70
71 while (i--) ds[i] = ~ds[i];
72 i = 0; num = 1;
73 do {
74 num += ds[i];
75 ds[i++] = BIGLO(num);
76 num = BIGDN(num);
77 } while (i < RBIGNUM(x)->len);
78 if (!carry) return;
79 if ((ds[RBIGNUM(x)->len-1] & (1<<(BITSPERDIG-1))) == 0) {
80 REALLOC_N(RBIGNUM(x)->digits, BDIGIT, ++RBIGNUM(x)->len);
81 ds = BDIGITS(x);
82 ds[RBIGNUM(x)->len-1] = ~0;
83 }
84 }
85
86 void
87 rb_big_2comp(x)
88 VALUE x;
89 {
90 get2comp(x, Qtrue);
91 }
92
93 static VALUE
94 bignorm(x)
95 VALUE x;
96 {
97 if (!FIXNUM_P(x)) {
98 long len = RBIGNUM(x)->len;
99 BDIGIT *ds = BDIGITS(x);
100
101 while (len-- && !ds[len]) ;
102 RBIGNUM(x)->len = ++len;
103
104 if (len*SIZEOF_BDIGITS <= sizeof(VALUE)) {
105 long num = 0;
106 while (len--) {
107 num = BIGUP(num) + ds[len];
108 }
109 if (num >= 0) {
110 if (RBIGNUM(x)->sign) {
111 if (POSFIXABLE(num)) return LONG2FIX(num);
112 }
113 else if (NEGFIXABLE(-(long)num)) return LONG2FIX(-(long)num);
114 }
115 }
116 }
117 return x;
118 }
119
120 VALUE
121 rb_big_norm(x)
122 VALUE x;
123 {
124 return bignorm(x);
125 }
126
127 VALUE
128 rb_uint2big(n)
129 unsigned long n;
130 {
131 BDIGIT_DBL num = n;
132 long i = 0;
133 BDIGIT *digits;
134 VALUE big;
135
136 big = bignew(DIGSPERLONG, 1);
137 digits = BDIGITS(big);
138 while (i < DIGSPERLONG) {
139 digits[i++] = BIGLO(num);
140 num = BIGDN(num);
141 }
142
143 i = DIGSPERLONG;
144 while (--i && !digits[i]) ;
145 RBIGNUM(big)->len = i+1;
146 return big;
147 }
148
149 VALUE
150 rb_int2big(n)
151 long n;
152 {
153 long neg = 0;
154 VALUE big;
155
156 if (n < 0) {
157 n = -n;
158 neg = 1;
159 }
160 big = rb_uint2big(n);
161 if (neg) {
162 RBIGNUM(big)->sign = 0;
163 }
164 return big;
165 }
166
167 VALUE
168 rb_uint2inum(n)
169 unsigned long n;
170 {
171 if (POSFIXABLE(n)) return LONG2FIX(n);
172 return rb_uint2big(n);
173 }
174
175 VALUE
176 rb_int2inum(n)
177 long n;
178 {
179 if (FIXABLE(n)) return LONG2FIX(n);
180 return rb_int2big(n);
181 }
182
183 #ifdef HAVE_LONG_LONG
184
185 #define DIGSPERLONGLONG ((unsigned int)(SIZEOF_LONG_LONG/SIZEOF_BDIGITS))
186
187 void
188 rb_quad_pack(buf, val)
189 char *buf;
190 VALUE val;
191 {
192 LONG_LONG q;
193
194 val = rb_to_int(val);
195 if (FIXNUM_P(val)) {
196 q = FIX2LONG(val);
197 }
198 else {
199 long len = RBIGNUM(val)->len;
200 BDIGIT *ds;
201
202 ds = BDIGITS(val);
203 q = 0;
204 while (len--) {
205 q = BIGUP(q);
206 q += ds[len];
207 }
208 }
209 memcpy(buf, (char*)&q, SIZEOF_LONG_LONG);
210 }
211
212 VALUE
213 rb_quad_unpack(buf, sign)
214 const char *buf;
215 int sign;
216 {
217 unsigned LONG_LONG q;
218 long neg = 0;
219 long i;
220 BDIGIT *digits;
221 VALUE big;
222
223 memcpy(&q, buf, SIZEOF_LONG_LONG);
224 if (sign) {
225 if (FIXABLE((LONG_LONG)q)) return LONG2FIX((LONG_LONG)q);
226 if ((LONG_LONG)q < 0) {
227 q = -(LONG_LONG)q;
228 neg = 1;
229 }
230 }
231 else {
232 if (POSFIXABLE(q)) return LONG2FIX(q);
233 }
234
235 i = 0;
236 big = bignew(DIGSPERLONGLONG, 1);
237 digits = BDIGITS(big);
238 while (i < DIGSPERLONGLONG) {
239 digits[i++] = BIGLO(q);
240 q = BIGDN(q);
241 }
242
243 i = DIGSPERLONGLONG;
244 while (i-- && !digits[i]) ;
245 RBIGNUM(big)->len = i+1;
246
247 if (neg) {
248 RBIGNUM(big)->sign = 0;
249 }
250 return bignorm(big);
251 }
252
253 #else
254
255 #define QUAD_SIZE 8
256
257 void
258 rb_quad_pack(buf, val)
259 char *buf;
260 VALUE val;
261 {
262 long len;
263
264 memset(buf, 0, QUAD_SIZE);
265 val = rb_to_int(val);
266 if (FIXNUM_P(val)) {
267 val = rb_int2big(FIX2LONG(val));
268 }
269 len = RBIGNUM(val)->len * SIZEOF_BDIGITS;
270 if (len > QUAD_SIZE) len = QUAD_SIZE;
271 memcpy(buf, (char*)BDIGITS(val), len);
272 if (!RBIGNUM(val)->sign) {
273 len = QUAD_SIZE;
274 while (len--) {
275 *buf = ~*buf;
276 buf++;
277 }
278 }
279 }
280
281 #define BNEG(b) (RSHIFT(((BDIGIT*)b)[QUAD_SIZE/SIZEOF_BDIGITS-1],BITSPERDIG-1) != 0)
282
283 VALUE
284 rb_quad_unpack(buf, sign)
285 const char *buf;
286 int sign;
287 {
288 VALUE big = bignew(QUAD_SIZE/SIZEOF_BDIGITS, 1);
289
290 memcpy((char*)BDIGITS(big), buf, QUAD_SIZE);
291 if (sign && BNEG(buf)) {
292 long len = QUAD_SIZE;
293 char *tmp = (char*)BDIGITS(big);
294
295 RBIGNUM(big)->sign = 0;
296 while (len--) {
297 *tmp = ~*tmp;
298 tmp++;
299 }
300 }
301
302 return bignorm(big);
303 }
304
305 #endif
306
307 VALUE
308 rb_cstr_to_inum(str, base, badcheck)
309 const char *str;
310 int base;
311 int badcheck;
312 {
313 const char *s = str;
314 char *end;
315 char sign = 1, c, nondigit = 0;
316 BDIGIT_DBL num;
317 long len, blen = 1;
318 long i;
319 VALUE z;
320 BDIGIT *zds;
321
322 if (badcheck) {
323 while (ISSPACE(*str)) str++;
324 }
325 else {
326 while (ISSPACE(*str) || *str == '_') str++;
327 }
328
329 if (str[0] == '+') {
330 str++;
331 }
332 else if (str[0] == '-') {
333 str++;
334 sign = 0;
335 }
336 if (str[0] == '+' || str[0] == '-') {
337 if (badcheck) goto bad;
338 return INT2FIX(0);
339 }
340 if (base <= 0) {
341 if (str[0] == '0') {
342 switch (str[1]) {
343 case 'x': case 'X':
344 base = 16;
345 break;
346 case 'b': case 'B':
347 base = 2;
348 break;
349 case 'o': case 'O':
350 base = 8;
351 break;
352 case 'd': case 'D':
353 base = 10;
354 break;
355 default:
356 base = 8;
357 }
358 }
359 else if (base < -1) {
360 base = -base;
361 }
362 else {
363 base = 10;
364 }
365 }
366 switch (base) {
367 case 2:
368 len = 1;
369 if (str[0] == '0' && (str[1] == 'b'||str[1] == 'B')) {
370 str += 2;
371 }
372 break;
373 case 8:
374 len = 3;
375 if (str[0] == '0' && (str[1] == 'o'||str[1] == 'O')) {
376 str += 2;
377 }
378 break;
379 case 10:
380 len = 4;
381 if (str[0] == '0' && (str[1] == 'd'||str[1] == 'D')) {
382 str += 2;
383 }
384 break;
385 case 16:
386 len = 4;
387 if (str[0] == '0' && (str[1] == 'x'||str[1] == 'X')) {
388 str += 2;
389 }
390 break;
391 }
392 if (*str == '0') {
393 while (*++str == '0');
394 --str;
395 }
396 len *= strlen(str)*sizeof(char);
397
398 if (len <= (sizeof(VALUE)*CHAR_BIT)) {
399 unsigned long val = strtoul((char*)str, &end, base);
400
401 if (*end == '_') goto bigparse;
402 if (badcheck) {
403 if (end == str) goto bad;
404 while (*end && ISSPACE(*end)) end++;
405 if (*end) {
406 bad:
407 rb_invalid_str(s, "Integer");
408 }
409 }
410
411 if (POSFIXABLE(val)) {
412 if (sign) return LONG2FIX(val);
413 else {
414 long result = -(long)val;
415 return LONG2FIX(result);
416 }
417 }
418 else {
419 VALUE big = rb_uint2big(val);
420 RBIGNUM(big)->sign = sign;
421 return bignorm(big);
422 }
423 }
424 bigparse:
425 len = (len/BITSPERDIG)+1;
426 if (badcheck && *str == '_') goto bad;
427
428 z = bignew(len, sign);
429 zds = BDIGITS(z);
430 for (i=len;i--;) zds[i]=0;
431 while (c = *str++) {
432 switch (c) {
433 case '8': case '9':
434 if (base == 8) {
435 c = base;
436 break;
437 }
438 case '0': case '1': case '2': case '3': case '4':
439 case '5': case '6': case '7':
440 c = c - '0';
441 nondigit = 0;
442 break;
443 case 'a': case 'b': case 'c':
444 case 'd': case 'e': case 'f':
445 c -= 'a' - 'A';
446 case 'A': case 'B': case 'C':
447 case 'D': case 'E': case 'F':
448 if (base != 16) {
449 nondigit = c;
450 c = base;
451 }
452 else {
453 c = c - 'A' + 10;
454 nondigit = 0;
455 }
456 break;
457 case '_':
458 if (badcheck) {
459 if (nondigit) goto bad;
460 nondigit = c;
461 }
462 continue;
463 default:
464 c = base;
465 break;
466 }
467 if (c >= base) break;
468 i = 0;
469 num = c;
470 for (;;) {
471 while (i<blen) {
472 num += (BDIGIT_DBL)zds[i]*base;
473 zds[i++] = BIGLO(num);
474 num = BIGDN(num);
475 }
476 if (num) {
477 blen++;
478 continue;
479 }
480 break;
481 }
482 }
483 if (badcheck) {
484 str--;
485 if (s+1 < str && str[-1] == '_') goto bad;
486 while (*str && ISSPACE(*str)) str++;
487 if (*str) goto bad;
488 }
489
490 return bignorm(z);
491 }
492
493 VALUE
494 rb_str_to_inum(str, base, badcheck)
495 VALUE str;
496 int base;
497 int badcheck;
498 {
499 char *s;
500 long len;
501
502 StringValue(str);
503 s = RSTRING(str)->ptr;
504 len = RSTRING(str)->len;
505 if (s[len]) {
506 char *p = ALLOCA_N(char, len+1);
507
508 MEMCPY(p, s, char, len);
509 p[len] = '\0';
510 s = p;
511 }
512 if (badcheck && len != strlen(s)) {
513 rb_raise(rb_eArgError, "string for Integer contains null byte");
514 }
515 return rb_cstr_to_inum(s, base, badcheck);
516 }
517
518 #if HAVE_LONG_LONG
519
520 VALUE
521 rb_ull2big(n)
522 unsigned LONG_LONG n;
523 {
524 BDIGIT_DBL num = n;
525 long i = 0;
526 BDIGIT *digits;
527 VALUE big;
528
529 big = bignew(DIGSPERLL, 1);
530 digits = BDIGITS(big);
531 while (i < DIGSPERLL) {
532 digits[i++] = BIGLO(num);
533 num = BIGDN(num);
534 }
535
536 i = DIGSPERLL;
537 while (i-- && !digits[i]) ;
538 RBIGNUM(big)->len = i+1;
539 return big;
540 }
541
542 VALUE
543 rb_ll2big(n)
544 LONG_LONG n;
545 {
546 long neg = 0;
547 VALUE big;
548
549 if (n < 0) {
550 n = -n;
551 neg = 1;
552 }
553 big = rb_ull2big(n);
554 if (neg) {
555 RBIGNUM(big)->sign = 0;
556 }
557 return big;
558 }
559
560 VALUE
561 rb_ull2inum(n)
562 unsigned LONG_LONG n;
563 {
564 if (POSFIXABLE(n)) return LONG2FIX(n);
565 return rb_ull2big(n);
566 }
567
568 VALUE
569 rb_ll2inum(n)
570 LONG_LONG n;
571 {
572 if (FIXABLE(n)) return LONG2FIX(n);
573 return rb_ll2big(n);
574 }
575
576 #endif
577
578 VALUE
579 rb_cstr2inum(str, base)
580 const char *str;
581 int base;
582 {
583 return rb_cstr_to_inum(str, base, base==0);
584 }
585
586 VALUE
587 rb_str2inum(str, base)
588 VALUE str;
589 int base;
590 {
591 return rb_str_to_inum(str, base, base==0);
592 }
593
594 static char hexmap[] = "0123456789abcdef";
595 VALUE
596 rb_big2str(x, base)
597 VALUE x;
598 int base;
599 {
600 volatile VALUE t;
601 BDIGIT *ds;
602 long i, j, hbase;
603 VALUE ss;
604 char *s, c;
605
606 if (FIXNUM_P(x)) {
607 return rb_fix2str(x, base);
608 }
609 i = RBIGNUM(x)->len;
610 if (i == 0 || (i == 1 && BDIGITS(x)[0] == 0)) {
611 return rb_str_new2("0");
612 }
613 if (base == 10) {
614 j = (SIZEOF_BDIGITS/sizeof(char)*CHAR_BIT*i*241L)/800+2;
615 hbase = 10000;
616 }
617 else if (base == 16) {
618 j = (SIZEOF_BDIGITS/sizeof(char)*CHAR_BIT*i)/4+2;
619 hbase = 0x10000;
620 }
621 else if (base == 8) {
622 j = (SIZEOF_BDIGITS/sizeof(char)*CHAR_BIT*i)+2;
623 hbase = 010000;
624 }
625 else if (base == 2) {
626 j = (SIZEOF_BDIGITS*CHAR_BIT*i)+2;
627 hbase = 020;
628 }
629 else {
630 rb_raise(rb_eArgError, "illegal radix %d", base);
631 }
632
633 t = rb_big_clone(x);
634 ds = BDIGITS(t);
635 ss = rb_str_new(0, j);
636 s = RSTRING(ss)->ptr;
637
638 s[0] = RBIGNUM(x)->sign ? '+' : '-';
639 while (i && j) {
640 long k = i;
641 BDIGIT_DBL num = 0;
642
643 while (k--) {
644 num = BIGUP(num) + ds[k];
645 ds[k] = (BDIGIT)(num / hbase);
646 num %= hbase;
647 }
648 if (ds[i-1] == 0) i--;
649 k = 4;
650 while (k--) {
651 c = (char)(num % base);
652 s[--j] = hexmap[(int)c];
653 num /= base;
654 if (i == 0 && num == 0) break;
655 }
656 }
657 while (s[j] == '0') j++;
658 RSTRING(ss)->len -= RBIGNUM(x)->sign?j:j-1;
659 memmove(RBIGNUM(x)->sign?s:s+1, s+j, RSTRING(ss)->len);
660 s[RSTRING(ss)->len] = '\0';
661
662 return ss;
663 }
664
665 static VALUE
666 rb_big_to_s(argc, argv, x)
667 int argc;
668 VALUE *argv;
669 VALUE x;
670 {
671 VALUE b;
672 int base;
673
674 rb_scan_args(argc, argv, "01", &b);
675 if (argc == 0) base = 10;
676 else base = NUM2INT(b);
677 return rb_big2str(x, base);
678 }
679
680 static unsigned long
681 big2ulong(x, type)
682 VALUE x;
683 char *type;
684 {
685 long len = RBIGNUM(x)->len;
686 BDIGIT_DBL num;
687 BDIGIT *ds;
688
689 if (len > SIZEOF_LONG/SIZEOF_BDIGITS)
690 rb_raise(rb_eRangeError, "bignum too big to convert into `%s'", type);
691 ds = BDIGITS(x);
692 num = 0;
693 while (len--) {
694 num = BIGUP(num);
695 num += ds[len];
696 }
697 return num;
698 }
699
700 unsigned long
701 rb_big2ulong(x)
702 VALUE x;
703 {
704 unsigned long num = big2ulong(x, "unsigned long");
705
706 if (!RBIGNUM(x)->sign) return -num;
707 return num;
708 }
709
710 long
711 rb_big2long(x)
712 VALUE x;
713 {
714 unsigned long num = big2ulong(x, "int");
715
716 if ((long)num < 0 && (RBIGNUM(x)->sign || (long)num != LONG_MIN)) {
717 rb_raise(rb_eRangeError, "bignum too big to convert into `int'");
718 }
719 if (!RBIGNUM(x)->sign) return -(long)num;
720 return num;
721 }
722
723 #if HAVE_LONG_LONG
724
725 static unsigned LONG_LONG
726 big2ull(x, type)
727 VALUE x;
728 char *type;
729 {
730 long len = RBIGNUM(x)->len;
731 BDIGIT_DBL num;
732 BDIGIT *ds;
733
734 if (len > SIZEOF_LONG_LONG/SIZEOF_BDIGITS)
735 rb_raise(rb_eRangeError, "bignum too big to convert into `%s'", type);
736 ds = BDIGITS(x);
737 num = 0;
738 while (len--) {
739 num = BIGUP(num);
740 num += ds[len];
741 }
742 return num;
743 }
744
745 unsigned LONG_LONG
746 rb_big2ull(x)
747 VALUE x;
748 {
749 unsigned LONG_LONG num = big2ull(x, "unsigned long long");
750
751 if (!RBIGNUM(x)->sign) return -num;
752 return num;
753 }
754
755 LONG_LONG
756 rb_big2ll(x)
757 VALUE x;
758 {
759 unsigned LONG_LONG num = big2ull(x, "long long");
760
761 if ((LONG_LONG)num < 0 && (RBIGNUM(x)->sign
762 || (LONG_LONG)num != LLONG_MIN)) {
763 rb_raise(rb_eRangeError, "bignum too big to convert into `long long'");
764 }
765 if (!RBIGNUM(x)->sign) return -(LONG_LONG)num;
766 return num;
767 }
768
769 #endif
770
771 static VALUE
772 dbl2big(d)
773 double d;
774 {
775 long i = 0;
776 BDIGIT c;
777 BDIGIT *digits;
778 VALUE z;
779 double u = (d < 0)?-d:d;
780
781 if (isinf(d)) {
782 rb_raise(rb_eFloatDomainError, d < 0 ? "-Infinity" : "Infinity");
783 }
784 if (isnan(d)) {
785 rb_raise(rb_eFloatDomainError, "NaN");
786 }
787
788 while (!POSFIXABLE(u) || 0 != (long)u) {
789 u /= (double)(BIGRAD);
790 i++;
791 }
792 z = bignew(i, d>=0);
793 digits = BDIGITS(z);
794 while (i--) {
795 u *= BIGRAD;
796 c = (BDIGIT)u;
797 u -= c;
798 digits[i] = c;
799 }
800
801 return z;
802 }
803
804 VALUE
805 rb_dbl2big(d)
806 double d;
807 {
808 return bignorm(dbl2big(d));
809 }
810
811 double
812 rb_big2dbl(x)
813 VALUE x;
814 {
815 double d = 0.0;
816 long i = RBIGNUM(x)->len;
817 BDIGIT *ds = BDIGITS(x);
818
819 while (i--) {
820 d = ds[i] + BIGRAD*d;
821 }
822 if (isinf(d)) d = HUGE_VAL;
823 if (!RBIGNUM(x)->sign) d = -d;
824 return d;
825 }
826
827 static VALUE
828 rb_big_to_f(x)
829 VALUE x;
830 {
831 return rb_float_new(rb_big2dbl(x));
832 }
833
834 static VALUE
835 rb_big_cmp(x, y)
836 VALUE x, y;
837 {
838 long xlen = RBIGNUM(x)->len;
839
840 switch (TYPE(y)) {
841 case T_FIXNUM:
842 y = rb_int2big(FIX2LONG(y));
843 break;
844
845 case T_BIGNUM:
846 break;
847
848 case T_FLOAT:
849 return rb_dbl_cmp(rb_big2dbl(x), RFLOAT(y)->value);
850
851 default:
852 return rb_num_coerce_bin(x, y);
853 }
854
855 if (RBIGNUM(x)->sign > RBIGNUM(y)->sign) return INT2FIX(1);
856 if (RBIGNUM(x)->sign < RBIGNUM(y)->sign) return INT2FIX(-1);
857 if (xlen < RBIGNUM(y)->len)
858 return (RBIGNUM(x)->sign) ? INT2FIX(-1) : INT2FIX(1);
859 if (xlen > RBIGNUM(y)->len)
860 return (RBIGNUM(x)->sign) ? INT2FIX(1) : INT2FIX(-1);
861
862 while(xlen-- && (BDIGITS(x)[xlen]==BDIGITS(y)[xlen]));
863 if (-1 == xlen) return INT2FIX(0);
864 return (BDIGITS(x)[xlen] > BDIGITS(y)[xlen]) ?
865 (RBIGNUM(x)->sign ? INT2FIX(1) : INT2FIX(-1)) :
866 (RBIGNUM(x)->sign ? INT2FIX(-1) : INT2FIX(1));
867 }
868
869 static VALUE
870 rb_big_eq(x, y)
871 VALUE x, y;
872 {
873 switch (TYPE(y)) {
874 case T_FIXNUM:
875 y = rb_int2big(FIX2LONG(y));
876 break;
877 case T_BIGNUM:
878 break;
879 case T_FLOAT:
880 if (rb_big2dbl(x) == RFLOAT(y)->value)
881 return Qtrue;
882 else
883 return Qfalse;
884 default:
885 return rb_equal(y, x);
886 }
887 if (RBIGNUM(x)->sign != RBIGNUM(y)->sign) return Qfalse;
888 if (RBIGNUM(x)->len != RBIGNUM(y)->len) return Qfalse;
889 if (MEMCMP(BDIGITS(x),BDIGITS(y),BDIGIT,RBIGNUM(y)->len) != 0) return Qfalse;
890 return Qtrue;
891 }
892
893 static VALUE
894 rb_big_eql(x, y)
895 VALUE x, y;
896 {
897 if (TYPE(y) != T_BIGNUM) return Qfalse;
898 if (RBIGNUM(x)->sign != RBIGNUM(y)->sign) return Qfalse;
899 if (RBIGNUM(x)->len != RBIGNUM(y)->len) return Qfalse;
900 if (MEMCMP(BDIGITS(x),BDIGITS(y),BDIGIT,RBIGNUM(y)->len) != 0) return Qfalse;
901 return Qtrue;
902 }
903
904 static VALUE
905 rb_big_uminus(x)
906 VALUE x;
907 {
908 VALUE z = rb_big_clone(x);
909
910 RBIGNUM(z)->sign = !RBIGNUM(x)->sign;
911
912 return bignorm(z);
913 }
914
915 static VALUE
916 rb_big_neg(x)
917 VALUE x;
918 {
919 VALUE z = rb_big_clone(x);
920 long i = RBIGNUM(x)->len;
921 BDIGIT *ds = BDIGITS(z);
922
923 if (!RBIGNUM(x)->sign) get2comp(z, Qtrue);
924 while (i--) ds[i] = ~ds[i];
925 if (RBIGNUM(x)->sign) get2comp(z, Qfalse);
926 RBIGNUM(z)->sign = !RBIGNUM(z)->sign;
927
928 return bignorm(z);
929 }
930
931 static VALUE
932 bigsub(x, y)
933 VALUE x, y;
934 {
935 VALUE z = 0;
936 BDIGIT *zds;
937 BDIGIT_DBL_SIGNED num;
938 long i = RBIGNUM(x)->len;
939
940
941 if (RBIGNUM(x)->len < RBIGNUM(y)->len) {
942 z = x; x = y; y = z;
943 }
944 else if (RBIGNUM(x)->len == RBIGNUM(y)->len) {
945 while (i > 0) {
946 i--;
947 if (BDIGITS(x)[i] > BDIGITS(y)[i]) {
948 break;
949 }
950 if (BDIGITS(x)[i] < BDIGITS(y)[i]) {
951 z = x; x = y; y = z;
952 break;
953 }
954 }
955 }
956
957 z = bignew(RBIGNUM(x)->len, (z == 0)?1:0);
958 zds = BDIGITS(z);
959
960 for (i = 0, num = 0; i < RBIGNUM(y)->len; i++) {
961 num += (BDIGIT_DBL_SIGNED)BDIGITS(x)[i] - BDIGITS(y)[i];
962 zds[i] = BIGLO(num);
963 num = BIGDN(num);
964 }
965 while (num && i < RBIGNUM(x)->len) {
966 num += BDIGITS(x)[i];
967 zds[i++] = BIGLO(num);
968 num = BIGDN(num);
969 }
970 while (i < RBIGNUM(x)->len) {
971 zds[i] = BDIGITS(x)[i];
972 i++;
973 }
974
975 return z;
976 }
977
978 static VALUE
979 bigadd(x, y, sign)
980 VALUE x, y;
981 char sign;
982 {
983 VALUE z;
984 BDIGIT_DBL num;
985 long i, len;
986
987 sign = (sign == RBIGNUM(y)->sign);
988 if (RBIGNUM(x)->sign != sign) {
989 if (sign) return bigsub(y, x);
990 return bigsub(x, y);
991 }
992
993 if (RBIGNUM(x)->len > RBIGNUM(y)->len) {
994 len = RBIGNUM(x)->len + 1;
995 z = x; x = y; y = z;
996 }
997 else {
998 len = RBIGNUM(y)->len + 1;
999 }
1000 z = bignew(len, sign);
1001
1002 len = RBIGNUM(x)->len;
1003 for (i = 0, num = 0; i < len; i++) {
1004 num += (BDIGIT_DBL)BDIGITS(x)[i] + BDIGITS(y)[i];
1005 BDIGITS(z)[i] = BIGLO(num);
1006 num = BIGDN(num);
1007 }
1008 len = RBIGNUM(y)->len;
1009 while (num && i < len) {
1010 num += BDIGITS(y)[i];
1011 BDIGITS(z)[i++] = BIGLO(num);
1012 num = BIGDN(num);
1013 }
1014 while (i < len) {
1015 BDIGITS(z)[i] = BDIGITS(y)[i];
1016 i++;
1017 }
1018 BDIGITS(z)[i] = (BDIGIT)num;
1019
1020 return z;
1021 }
1022
1023 VALUE
1024 rb_big_plus(x, y)
1025 VALUE x, y;
1026 {
1027 switch (TYPE(y)) {
1028 case T_FIXNUM:
1029 y = rb_int2big(FIX2LONG(y));
1030
1031 case T_BIGNUM:
1032 return bignorm(bigadd(x, y, 1));
1033
1034 case T_FLOAT:
1035 return rb_float_new(rb_big2dbl(x) + RFLOAT(y)->value);
1036
1037 default:
1038 return rb_num_coerce_bin(x, y);
1039 }
1040 }
1041
1042 VALUE
1043 rb_big_minus(x, y)
1044 VALUE x, y;
1045 {
1046 switch (TYPE(y)) {
1047 case T_FIXNUM:
1048 y = rb_int2big(FIX2LONG(y));
1049
1050 case T_BIGNUM:
1051 return bignorm(bigadd(x, y, 0));
1052
1053 case T_FLOAT:
1054 return rb_float_new(rb_big2dbl(x) - RFLOAT(y)->value);
1055
1056 default:
1057 return rb_num_coerce_bin(x, y);
1058 }
1059 }
1060
1061 VALUE
1062 rb_big_mul(x, y)
1063 VALUE x, y;
1064 {
1065 long i, j;
1066 BDIGIT_DBL n = 0;
1067 VALUE z;
1068 BDIGIT *zds;
1069
1070 if (FIXNUM_P(x)) x = rb_int2big(FIX2LONG(x));
1071 switch (TYPE(y)) {
1072 case T_FIXNUM:
1073 y = rb_int2big(FIX2LONG(y));
1074 break;
1075
1076 case T_BIGNUM:
1077 break;
1078
1079 case T_FLOAT:
1080 return rb_float_new(rb_big2dbl(x) * RFLOAT(y)->value);
1081
1082 default:
1083 return rb_num_coerce_bin(x, y);
1084 }
1085
1086 j = RBIGNUM(x)->len + RBIGNUM(y)->len + 1;
1087 z = bignew(j, RBIGNUM(x)->sign==RBIGNUM(y)->sign);
1088 zds = BDIGITS(z);
1089 while (j--) zds[j] = 0;
1090 for (i = 0; i < RBIGNUM(x)->len; i++) {
1091 BDIGIT_DBL dd = BDIGITS(x)[i];
1092 if (dd == 0) continue;
1093 n = 0;
1094 for (j = 0; j < RBIGNUM(y)->len; j++) {
1095 BDIGIT_DBL ee = n + (BDIGIT_DBL)dd * BDIGITS(y)[j];
1096 n = zds[i + j] + ee;
1097 if (ee) zds[i + j] = BIGLO(n);
1098 n = BIGDN(n);
1099 }
1100 if (n) {
1101 zds[i + j] = n;
1102 }
1103 }
1104
1105 return bignorm(z);
1106 }
1107
1108 static void
1109 bigdivrem(x, y, divp, modp)
1110 VALUE x, y;
1111 VALUE *divp, *modp;
1112 {
1113 long nx = RBIGNUM(x)->len, ny = RBIGNUM(y)->len;
1114 long i, j;
1115 VALUE yy, z;
1116 BDIGIT *xds, *yds, *zds, *tds;
1117 BDIGIT_DBL t2;
1118 BDIGIT_DBL_SIGNED num;
1119 BDIGIT dd, q;
1120
1121 yds = BDIGITS(y);
1122 if (ny == 0 && yds[0] == 0) rb_num_zerodiv();
1123 if (nx < ny || nx == ny && BDIGITS(x)[nx - 1] < BDIGITS(y)[ny - 1]) {
1124 if (divp) *divp = rb_int2big(0);
1125 if (modp) *modp = x;
1126 return;
1127 }
1128 xds = BDIGITS(x);
1129 if (ny == 1) {
1130 dd = yds[0];
1131 z = rb_big_clone(x);
1132 zds = BDIGITS(z);
1133 t2 = 0; i = nx;
1134 while (i--) {
1135 t2 = BIGUP(t2) + zds[i];
1136 zds[i] = (BDIGIT)(t2 / dd);
1137 t2 %= dd;
1138 }
1139 RBIGNUM(z)->sign = RBIGNUM(x)->sign==RBIGNUM(y)->sign;
1140 if (modp) {
1141 *modp = rb_uint2big((unsigned long)t2);
1142 RBIGNUM(*modp)->sign = RBIGNUM(x)->sign;
1143 }
1144 if (divp) *divp = z;
1145 return;
1146 }
1147 z = bignew(nx==ny?nx+2:nx+1, RBIGNUM(x)->sign==RBIGNUM(y)->sign);
1148 zds = BDIGITS(z);
1149 if (nx==ny) zds[nx+1] = 0;
1150 while (!yds[ny-1]) ny--;
1151
1152 dd = 0;
1153 q = yds[ny-1];
1154 while ((q & (1<<(BITSPERDIG-1))) == 0) {
1155 q <<= 1;
1156 dd++;
1157 }
1158 if (dd) {
1159 yy = rb_big_clone(y);
1160 tds = BDIGITS(yy);
1161 j = 0;
1162 t2 = 0;
1163 while (j<ny) {
1164 t2 += (BDIGIT_DBL)yds[j]<<dd;
1165 tds[j++] = BIGLO(t2);
1166 t2 = BIGDN(t2);
1167 }
1168 yds = tds;
1169 j = 0;
1170 t2 = 0;
1171 while (j<nx) {
1172 t2 += (BDIGIT_DBL)xds[j]<<dd;
1173 zds[j++] = BIGLO(t2);
1174 t2 = BIGDN(t2);
1175 }
1176 zds[j] = (BDIGIT)t2;
1177 }
1178 else {
1179 zds[nx] = 0;
1180 j = nx;
1181 while (j--) zds[j] = xds[j];
1182 }
1183
1184 j = nx==ny?nx+1:nx;
1185 do {
1186 if (zds[j] == yds[ny-1]) q = BIGRAD-1;
1187 else q = (BDIGIT)((BIGUP(zds[j]) + zds[j-1])/yds[ny-1]);
1188 if (q) {
1189 i = 0; num = 0; t2 = 0;
1190 do {
1191 BDIGIT_DBL ee;
1192 t2 += (BDIGIT_DBL)yds[i] * q;
1193 ee = num - BIGLO(t2);
1194 num = (BDIGIT_DBL)zds[j - ny + i] + ee;
1195 if (ee) zds[j - ny + i] = BIGLO(num);
1196 num = BIGDN(num);
1197 t2 = BIGDN(t2);
1198 } while (++i < ny);
1199 num += zds[j - ny + i] - t2;
1200 while (num) {
1201 i = 0; num = 0; q--;
1202 do {
1203 BDIGIT_DBL ee = num + yds[i];
1204 num = (BDIGIT_DBL)zds[j - ny + i] + ee;
1205 if (ee) zds[j - ny + i] = BIGLO(num);
1206 num = BIGDN(num);
1207 } while (++i < ny);
1208 num--;
1209 }
1210 }
1211 zds[j] = q;
1212 } while (--j >= ny);
1213 if (divp) {
1214 *divp = rb_big_clone(z);
1215 zds = BDIGITS(*divp);
1216 j = (nx==ny ? nx+2 : nx+1) - ny;
1217 for (i = 0;i < j;i++) zds[i] = zds[i+ny];
1218 RBIGNUM(*divp)->len = i;
1219 }
1220 if (modp) {
1221 *modp = rb_big_clone(z);
1222 zds = BDIGITS(*modp);
1223 while (ny-- && !zds[ny]); ++ny;
1224 if (dd) {
1225 t2 = 0; i = ny;
1226 while(i--) {
1227 t2 = (t2 | zds[i]) >> dd;
1228 q = zds[i];
1229 zds[i] = BIGLO(t2);
1230 t2 = BIGUP(q);
1231 }
1232 }
1233 RBIGNUM(*modp)->len = ny;
1234 RBIGNUM(*modp)->sign = RBIGNUM(x)->sign;
1235 }
1236 }
1237
1238 static void
1239 bigdivmod(x, y, divp, modp)
1240 VALUE x, y;
1241 VALUE *divp, *modp;
1242 {
1243 VALUE mod;
1244
1245 bigdivrem(x, y, divp, &mod);
1246 if (RBIGNUM(x)->sign != RBIGNUM(y)->sign && RBIGNUM(mod)->len > 0) {
1247 if (divp) *divp = bigadd(*divp, rb_int2big(1), 0);
1248 if (modp) *modp = bigadd(mod, y, 1);
1249 }
1250 else {
1251 if (divp) *divp = *divp;
1252 if (modp) *modp = mod;
1253 }
1254 }
1255
1256 static VALUE
1257 rb_big_div(x, y)
1258 VALUE x, y;
1259 {
1260 VALUE z;
1261
1262 switch (TYPE(y)) {
1263 case T_FIXNUM:
1264 y = rb_int2big(FIX2LONG(y));
1265 break;
1266
1267 case T_BIGNUM:
1268 break;
1269
1270 case T_FLOAT:
1271 return rb_float_new(rb_big2dbl(x) / RFLOAT(y)->value);
1272
1273 default:
1274 return rb_num_coerce_bin(x, y);
1275 }
1276 bigdivmod(x, y, &z, 0);
1277
1278 return bignorm(z);
1279 }
1280
1281
1282 static VALUE
1283 rb_big_modulo(x, y)
1284 VALUE x, y;
1285 {
1286 VALUE z;
1287
1288 switch (TYPE(y)) {
1289 case T_FIXNUM:
1290 y = rb_int2big(FIX2LONG(y));
1291 break;
1292
1293 case T_BIGNUM:
1294 break;
1295
1296 default:
1297 return rb_num_coerce_bin(x, y);
1298 }
1299 bigdivmod(x, y, 0, &z);
1300
1301 return bignorm(z);
1302 }
1303
1304 static VALUE
1305 rb_big_remainder(x, y)
1306 VALUE x, y;
1307 {
1308 VALUE z;
1309
1310 switch (TYPE(y)) {
1311 case T_FIXNUM:
1312 y = rb_int2big(FIX2LONG(y));
1313 break;
1314
1315 case T_BIGNUM:
1316 break;
1317
1318 default:
1319 return rb_num_coerce_bin(x, y);
1320 }
1321 bigdivrem(x, y, 0, &z);
1322
1323 return bignorm(z);
1324 }
1325
1326 VALUE
1327 rb_big_divmod(x, y)
1328 VALUE x, y;
1329 {
1330 VALUE div, mod;
1331
1332 switch (TYPE(y)) {
1333 case T_FIXNUM:
1334 y = rb_int2big(FIX2LONG(y));
1335 break;
1336
1337 case T_BIGNUM:
1338 break;
1339
1340 default:
1341 return rb_num_coerce_bin(x, y);
1342 }
1343 bigdivmod(x, y, &div, &mod);
1344
1345 return rb_assoc_new(bignorm(div), bignorm(mod));
1346 }
1347
1348 VALUE
1349 rb_big_pow(x, y)
1350 VALUE x, y;
1351 {
1352 double d;
1353 long yy;
1354
1355 if (y == INT2FIX(0)) return INT2FIX(1);
1356 switch (TYPE(y)) {
1357 case T_FLOAT:
1358 d = RFLOAT(y)->value;
1359 break;
1360
1361 case T_BIGNUM:
1362 rb_warn("in a**b, b may be too big");
1363 d = rb_big2dbl(y);
1364 break;
1365
1366 case T_FIXNUM:
1367 yy = NUM2LONG(y);
1368 if (yy > 0) {
1369 VALUE z = x;
1370
1371 for (;;) {
1372 yy -= 1;
1373 if (yy == 0) break;
1374 while (yy % 2 == 0) {
1375 yy /= 2;
1376 x = rb_big_mul(x, x);
1377 }
1378 z = rb_big_mul(z, x);
1379 }
1380 return bignorm(z);
1381 }
1382 d = (double)yy;
1383 break;
1384
1385 default:
1386 return rb_num_coerce_bin(x, y);
1387 }
1388 return rb_float_new(pow(rb_big2dbl(x), d));
1389 }
1390
1391 VALUE
1392 rb_big_and(x, y)
1393 VALUE x, y;
1394 {
1395 VALUE z;
1396 BDIGIT *ds1, *ds2, *zds;
1397 long i, l1, l2;
1398 char sign;
1399
1400 if (FIXNUM_P(y)) {
1401 y = rb_int2big(FIX2LONG(y));
1402 }
1403 else {
1404 Check_Type(y, T_BIGNUM);
1405 }
1406
1407 if (!RBIGNUM(y)->sign) {
1408 y = rb_big_clone(y);
1409 get2comp(y, Qtrue);
1410 }
1411 if (!RBIGNUM(x)->sign) {
1412 x = rb_big_clone(x);
1413 get2comp(x, Qtrue);
1414 }
1415 if (RBIGNUM(x)->len > RBIGNUM(y)->len) {
1416 l1 = RBIGNUM(y)->len;
1417 l2 = RBIGNUM(x)->len;
1418 ds1 = BDIGITS(y);
1419 ds2 = BDIGITS(x);
1420 sign = RBIGNUM(y)->sign;
1421 }
1422 else {
1423 l1 = RBIGNUM(x)->len;
1424 l2 = RBIGNUM(y)->len;
1425 ds1 = BDIGITS(x);
1426 ds2 = BDIGITS(y);
1427 sign = RBIGNUM(x)->sign;
1428 }
1429 z = bignew(l2, RBIGNUM(x)->sign || RBIGNUM(y)->sign);
1430 zds = BDIGITS(z);
1431
1432 for (i=0; i<l1; i++) {
1433 zds[i] = ds1[i] & ds2[i];
1434 }
1435 for (; i<l2; i++) {
1436 zds[i] = sign?0:ds2[i];
1437 }
1438 if (!RBIGNUM(z)->sign) get2comp(z, Qfalse);
1439 return bignorm(z);
1440 }
1441
1442 VALUE
1443 rb_big_or(x, y)
1444 VALUE x, y;
1445 {
1446 VALUE z;
1447 BDIGIT *ds1, *ds2, *zds;
1448 long i, l1, l2;
1449 char sign;
1450
1451 if (FIXNUM_P(y)) {
1452 y = rb_int2big(FIX2LONG(y));
1453 }
1454 else {
1455 Check_Type(y, T_BIGNUM);
1456 }
1457
1458 if (!RBIGNUM(y)->sign) {
1459 y = rb_big_clone(y);
1460 get2comp(y, Qtrue);
1461 }
1462 if (!RBIGNUM(x)->sign) {
1463 x = rb_big_clone(x);
1464 get2comp(x, Qtrue);
1465 }
1466 if (RBIGNUM(x)->len > RBIGNUM(y)->len) {
1467 l1 = RBIGNUM(y)->len;
1468 l2 = RBIGNUM(x)->len;
1469 ds1 = BDIGITS(y);
1470 ds2 = BDIGITS(x);
1471 sign = RBIGNUM(y)->sign;
1472 }
1473 else {
1474 l1 = RBIGNUM(x)->len;
1475 l2 = RBIGNUM(y)->len;
1476 ds1 = BDIGITS(x);
1477 ds2 = BDIGITS(y);
1478 sign = RBIGNUM(x)->sign;
1479 }
1480 z = bignew(l2, RBIGNUM(x)->sign && RBIGNUM(y)->sign);
1481 zds = BDIGITS(z);
1482
1483 for (i=0; i<l1; i++) {
1484 zds[i] = ds1[i] | ds2[i];
1485 }
1486 for (; i<l2; i++) {
1487 zds[i] = sign?ds2[i]:(BIGRAD-1);
1488 }
1489 if (!RBIGNUM(z)->sign) get2comp(z, Qfalse);
1490
1491 return bignorm(z);
1492 }
1493
1494 VALUE
1495 rb_big_xor(x, y)
1496 VALUE x, y;
1497 {
1498 VALUE z;
1499 BDIGIT *ds1, *ds2, *zds;
1500 long i, l1, l2;
1501 char sign;
1502
1503 if (FIXNUM_P(y)) {
1504 y = rb_int2big(FIX2LONG(y));
1505 }
1506 else {
1507 Check_Type(y, T_BIGNUM);
1508 }
1509
1510 if (!RBIGNUM(y)->sign) {
1511 y = rb_big_clone(y);
1512 get2comp(y, Qtrue);
1513 }
1514 if (!RBIGNUM(x)->sign) {
1515 x = rb_big_clone(x);
1516 get2comp(x, Qtrue);
1517 }
1518 if (RBIGNUM(x)->len > RBIGNUM(y)->len) {
1519 l1 = RBIGNUM(y)->len;
1520 l2 = RBIGNUM(x)->len;
1521 ds1 = BDIGITS(y);
1522 ds2 = BDIGITS(x);
1523 sign = RBIGNUM(y)->sign;
1524 }
1525 else {
1526 l1 = RBIGNUM(x)->len;
1527 l2 = RBIGNUM(y)->len;
1528 ds1 = BDIGITS(x);
1529 ds2 = BDIGITS(y);
1530 sign = RBIGNUM(x)->sign;
1531 }
1532 RBIGNUM(x)->sign = RBIGNUM(x)->sign?1:0;
1533 RBIGNUM(y)->sign = RBIGNUM(y)->sign?1:0;
1534 z = bignew(l2, !(RBIGNUM(x)->sign ^ RBIGNUM(y)->sign));
1535 zds = BDIGITS(z);
1536
1537 for (i=0; i<l1; i++) {
1538 zds[i] = ds1[i] ^ ds2[i];
1539 }
1540 for (; i<l2; i++) {
1541 zds[i] = sign?ds2[i]:~ds2[i];
1542 }
1543 if (!RBIGNUM(z)->sign) get2comp(z, Qfalse);
1544
1545 return bignorm(z);
1546 }
1547
1548 static VALUE rb_big_rshift _((VALUE,VALUE));
1549
1550 VALUE
1551 rb_big_lshift(x, y)
1552 VALUE x, y;
1553 {
1554 BDIGIT *xds, *zds;
1555 int shift = NUM2INT(y);
1556 int s1 = shift/BITSPERDIG;
1557 int s2 = shift%BITSPERDIG;
1558 VALUE z;
1559 BDIGIT_DBL num = 0;
1560 long len, i;
1561
1562 if (shift < 0) return rb_big_rshift(x, INT2FIX(-shift));
1563 len = RBIGNUM(x)->len;
1564 z = bignew(len+s1+1, RBIGNUM(x)->sign);
1565 zds = BDIGITS(z);
1566 for (i=0; i<s1; i++) {
1567 *zds++ = 0;
1568 }
1569 xds = BDIGITS(x);
1570 for (i=0; i<len; i++) {
1571 num = num | (BDIGIT_DBL)*xds++<<s2;
1572 *zds++ = BIGLO(num);
1573 num = BIGDN(num);
1574 }
1575 *zds = BIGLO(num);
1576 return bignorm(z);
1577 }
1578
1579 static VALUE
1580 rb_big_rshift(x, y)
1581 VALUE x, y;
1582 {
1583 BDIGIT *xds, *zds;
1584 int shift = NUM2INT(y);
1585 long s1 = shift/BITSPERDIG;
1586 long s2 = shift%BITSPERDIG;
1587 VALUE z;
1588 BDIGIT_DBL num = 0;
1589 long i, j;
1590
1591 if (shift < 0) return rb_big_lshift(x, INT2FIX(-shift));
1592
1593 if (s1 > RBIGNUM(x)->len) {
1594 if (RBIGNUM(x)->sign)
1595 return INT2FIX(0);
1596 else
1597 return INT2FIX(-1);
1598 }
1599 if (!RBIGNUM(x)->sign) {
1600 x = rb_big_clone(x);
1601 get2comp(x, Qtrue);
1602 }
1603 xds = BDIGITS(x);
1604 i = RBIGNUM(x)->len; j = i - s1;
1605 z = bignew(j, RBIGNUM(x)->sign);
1606 zds = BDIGITS(z);
1607 while (i--, j--) {
1608 num = (num | xds[i]) >> s2;
1609 zds[j] = BIGLO(num);
1610 num = BIGUP(xds[i]);
1611 }
1612 if (!RBIGNUM(x)->sign) {
1613 get2comp(z, Qfalse);
1614 }
1615 return bignorm(z);
1616 }
1617
1618 static VALUE
1619 rb_big_aref(x, y)
1620 VALUE x, y;
1621 {
1622 BDIGIT *xds;
1623 int shift;
1624 long s1, s2;
1625
1626 if (TYPE(y) == T_BIGNUM) {
1627 if (!RBIGNUM(y)->sign || RBIGNUM(x)->sign)
1628 return INT2FIX(0);
1629 return INT2FIX(1);
1630 }
1631 shift = NUM2INT(y);
1632 if (shift < 0) return INT2FIX(0);
1633 s1 = shift/BITSPERDIG;
1634 s2 = shift%BITSPERDIG;
1635
1636 if (!RBIGNUM(x)->sign) {
1637 if (s1 >= RBIGNUM(x)->len) return INT2FIX(1);
1638 x = rb_big_clone(x);
1639 get2comp(x, Qtrue);
1640 }
1641 else {
1642 if (s1 >= RBIGNUM(x)->len) return INT2FIX(0);
1643 }
1644 xds = BDIGITS(x);
1645 if (xds[s1] & (1<<s2))
1646 return INT2FIX(1);
1647 return INT2FIX(0);
1648 }
1649
1650 static VALUE
1651 rb_big_hash(x)
1652 VALUE x;
1653 {
1654 long i, len, key;
1655 BDIGIT *digits;
1656
1657 key = 0; digits = BDIGITS(x); len = RBIGNUM(x)->len;
1658 for (i=0; i<len; i++) {
1659 key ^= *digits++;
1660 }
1661 return LONG2FIX(key);
1662 }
1663
1664 static VALUE
1665 rb_big_coerce(x, y)
1666 VALUE x, y;
1667 {
1668 if (FIXNUM_P(y)) {
1669 return rb_assoc_new(rb_int2big(FIX2LONG(y)), x);
1670 }
1671 else {
1672 rb_raise(rb_eTypeError, "Can't coerce %s to Bignum",
1673 rb_class2name(CLASS_OF(y)));
1674 }
1675
1676 return Qnil;
1677 }
1678
1679 static VALUE
1680 rb_big_abs(x)
1681 VALUE x;
1682 {
1683 if (!RBIGNUM(x)->sign) {
1684 x = rb_big_clone(x);
1685 RBIGNUM(x)->sign = 1;
1686 }
1687 return x;
1688 }
1689
1690 VALUE
1691 rb_big_rand(max, rand_buf)
1692 VALUE max;
1693 double *rand_buf;
1694 {
1695 VALUE v;
1696 long len = RBIGNUM(max)->len;
1697
1698 if (len == 0 && BDIGITS(max)[0] == 0) {
1699 return rb_float_new(rand_buf[0]);
1700 }
1701 v = bignew(len,1);
1702 while (len--) {
1703 BDIGITS(v)[len] = ((BDIGIT)~0) * rand_buf[len];
1704 }
1705
1706 return rb_big_modulo((VALUE)v, max);
1707 }
1708
1709 static VALUE
1710 rb_big_size(big)
1711 VALUE big;
1712 {
1713 return LONG2FIX(RBIGNUM(big)->len*SIZEOF_BDIGITS);
1714 }
1715
1716 void
1717 Init_Bignum()
1718 {
1719 rb_cBignum = rb_define_class("Bignum", rb_cInteger);
1720
1721 rb_define_method(rb_cBignum, "to_s", rb_big_to_s, -1);
1722 rb_define_method(rb_cBignum, "coerce", rb_big_coerce, 1);
1723 rb_define_method(rb_cBignum, "-@", rb_big_uminus, 0);
1724 rb_define_method(rb_cBignum, "+", rb_big_plus, 1);
1725 rb_define_method(rb_cBignum, "-", rb_big_minus, 1);
1726 rb_define_method(rb_cBignum, "*", rb_big_mul, 1);
1727 rb_define_method(rb_cBignum, "/", rb_big_div, 1);
1728 rb_define_method(rb_cBignum, "%", rb_big_modulo, 1);
1729 rb_define_method(rb_cBignum, "divmod", rb_big_divmod, 1);
1730 rb_define_method(rb_cBignum, "modulo", rb_big_modulo, 1);
1731 rb_define_method(rb_cBignum, "remainder", rb_big_remainder, 1);
1732 rb_define_method(rb_cBignum, "**", rb_big_pow, 1);
1733 rb_define_method(rb_cBignum, "&", rb_big_and, 1);
1734 rb_define_method(rb_cBignum, "|", rb_big_or, 1);
1735 rb_define_method(rb_cBignum, "^", rb_big_xor, 1);
1736 rb_define_method(rb_cBignum, "~", rb_big_neg, 0);
1737 rb_define_method(rb_cBignum, "<<", rb_big_lshift, 1);
1738 rb_define_method(rb_cBignum, ">>", rb_big_rshift, 1);
1739 rb_define_method(rb_cBignum, "[]", rb_big_aref, 1);
1740
1741 rb_define_method(rb_cBignum, "<=>", rb_big_cmp, 1);
1742 rb_define_method(rb_cBignum, "==", rb_big_eq, 1);
1743 rb_define_method(rb_cBignum, "===", rb_big_eq, 1);
1744 rb_define_method(rb_cBignum, "eql?", rb_big_eql, 1);
1745 rb_define_method(rb_cBignum, "hash", rb_big_hash, 0);
1746 rb_define_method(rb_cBignum, "to_f", rb_big_to_f, 0);
1747 rb_define_method(rb_cBignum, "abs", rb_big_abs, 0);
1748 rb_define_method(rb_cBignum, "size", rb_big_size, 0);
1749 }