4 #include "shotgun/lib/shotgun.h"
5 #include "shotgun/lib/string.h"
7 #define NMP mp_int *n; OBJECT n_obj; \
8 NEW_STRUCT(n_obj, n, BASIC_CLASS(bignum), mp_int); \
10 #define MMP mp_int *m; OBJECT m_obj; \
11 NEW_STRUCT(m_obj, m, BASIC_CLASS(bignum), mp_int); \
15 #define MP(k) DATA_STRUCT(k, mp_int*)
16 #define BDIGIT_DBL long long
17 #define DIGIT_RADIX (1L << DIGIT_BIT)
19 void bignum_cleanup(STATE
, OBJECT obj
) {
24 void bignum_init(STATE
) {
25 state_add_cleanup(state
, BASIC_CLASS(bignum
), bignum_cleanup
);
28 static void twos_complement(mp_int
*a
)
34 DIGIT(a
,i
) = (~DIGIT(a
,i
)) & (DIGIT_RADIX
-1);
40 DIGIT(a
,i
++) = num
& (DIGIT_RADIX
-1);
41 num
= num
>> DIGIT_BIT
;
42 } while (i
< a
->used
);
46 OBJECT
bignum_new(STATE
, native_int num
) {
49 o
= object_memory_new_opaque(state
, BASIC_CLASS(bignum
), sizeof(mp_int
));
50 a
= (mp_int
*)BYTES_OF(o
);
53 mp_init_set_long(a
, (unsigned long)-num
);
56 mp_init_set_long(a
, (unsigned long)num
);
61 OBJECT
bignum_new_unsigned(STATE
, unsigned int num
) {
63 o
= object_memory_new_opaque(state
, BASIC_CLASS(bignum
), sizeof(mp_int
));
64 mp_init_set_int(MP(o
), num
);
68 static inline OBJECT
bignum_normalize(STATE
, OBJECT b
) {
71 if(mp_count_bits(MP(b
)) <= FIXNUM_WIDTH
) {
73 val
= (native_int
)bignum_to_ll(state
, b
);
79 OBJECT
bignum_add(STATE
, OBJECT a
, OBJECT b
) {
84 mp_sub_d(MP(a
), -N2I(b
), n
);
86 mp_add_d(MP(a
), N2I(b
), n
);
89 mp_add(MP(a
), MP(b
), n
);
92 return bignum_normalize(state
, n_obj
);
95 OBJECT
bignum_sub(STATE
, OBJECT a
, OBJECT b
) {
100 mp_add_d(MP(a
), -N2I(b
), n
);
102 mp_sub_d(MP(a
), N2I(b
), n
);
105 mp_sub(MP(a
), MP(b
), n
);
108 return bignum_normalize(state
, n_obj
);
111 void bignum_debug(STATE
, OBJECT n
) {
112 char *stra
= XMALLOC(2048);
113 mp_toradix(MP(n
), stra
, 10);
114 printf("n: %s\n", stra
);
119 OBJECT
bignum_mul(STATE
, OBJECT a
, OBJECT b
) {
128 /* mp_mul_d only accepts positive integers (unsigned long).
129 * Therefore we jump through some hoops to negate
130 * both parts so the final result is the same.
133 mp_mul_d(n
, -N2I(b
), n
);
135 mp_mul_d(MP(a
), N2I(b
), n
);
138 mp_mul(MP(a
), MP(b
), n
);
141 return bignum_normalize(state
, n_obj
);
144 OBJECT
bignum_div(STATE
, OBJECT a
, OBJECT b
, mp_int
*mod
) {
149 b
= bignum_new(state
, N2I(b
));
157 if(mp_cmp_d(MP(b
), 0) == MP_LT
) {
158 if(mp_cmp_d(MP(a
), 0) == MP_LT
) {
161 mp_div(&x
, &y
, &z
, NULL
);
164 mp_div(MP(a
), &x
, &y
, NULL
);
168 if (mp_cmp_d(MP(a
), 0) == MP_LT
) {
170 mp_div(&x
, MP(b
), &y
, NULL
);
173 mp_div(MP(a
), MP(b
), &z
, NULL
);
177 mp_mul(&z
, MP(b
), &x
);
178 mp_sub(MP(a
), &x
, &y
);
180 if((mp_cmp_d(&y
, 0) == MP_LT
&& mp_cmp_d(MP(b
), 0) == MP_GT
)
181 || (mp_cmp_d(&y
, 0) == MP_GT
&& mp_cmp_d(MP(b
), 0) == MP_LT
)) {
182 mp_add(&y
, MP(b
), &m
);
198 return bignum_normalize(state
, n_obj
);
201 OBJECT
bignum_divmod(STATE
, OBJECT a
, OBJECT b
) {
205 div
= bignum_div(state
, a
, b
, m
);
207 ary
= array_new(state
, 2);
208 array_set(state
, ary
, 0, div
);
209 array_set(state
, ary
, 1, bignum_normalize(state
, m_obj
));
213 OBJECT
bignum_mod(STATE
, OBJECT a
, OBJECT b
) {
217 b
= bignum_new(state
, N2I(b
));
219 mp_mod(MP(a
), MP(b
), n
);
220 return bignum_normalize(state
, n_obj
);
223 int bignum_is_zero(STATE
, OBJECT a
) {
224 return mp_iszero(MP(a
)) ? TRUE
: FALSE
;
227 #define BITWISE_OP_AND 1
228 #define BITWISE_OP_OR 2
229 #define BITWISE_OP_XOR 3
231 void bignum_bitwise_op(int op
, mp_int
*x
, mp_int
*y
, mp_int
*n
)
236 mp_init(&a
) ; mp_init(&b
);
238 if (y
->sign
== MP_NEG
) {
244 if (x
->sign
== MP_NEG
) {
250 if (x
->used
> y
->used
) {
269 if (x
->sign
== MP_NEG
&& y
->sign
== MP_NEG
) n
->sign
= MP_NEG
;
270 for (i
=0; i
< l1
; i
++) {
271 DIGIT(n
,i
) = DIGIT(d1
,i
) & DIGIT(d2
,i
);
273 for (; i
< l2
; i
++) {
274 DIGIT(n
,i
) = (sign
== MP_ZPOS
)?0:DIGIT(d2
,i
);
278 if (x
->sign
== MP_NEG
|| y
->sign
== MP_NEG
) n
->sign
= MP_NEG
;
279 for (i
=0; i
< l1
; i
++) {
280 DIGIT(n
,i
) = DIGIT(d1
,i
) | DIGIT(d2
,i
);
282 for (; i
< l2
; i
++) {
283 DIGIT(n
,i
) = (sign
== MP_ZPOS
)?DIGIT(d2
,i
):(DIGIT_RADIX
-1);
287 if (x
->sign
!= y
->sign
) n
->sign
= MP_NEG
;
288 for (i
=0; i
< l1
; i
++) {
289 DIGIT(n
,i
) = DIGIT(d1
,i
) ^ DIGIT(d2
,i
);
291 for (; i
< l2
; i
++) {
292 DIGIT(n
,i
) = (sign
== MP_ZPOS
)?DIGIT(d2
,i
):~DIGIT(d2
,i
);
297 if (n
->sign
== MP_NEG
) twos_complement(n
);
299 /* free allocated resources for twos complement copies */
304 OBJECT
bignum_and(STATE
, OBJECT a
, OBJECT b
) {
308 b
= bignum_new(state
, N2I(b
));
311 /* Perhaps this should use mp_and rather than our own version */
312 bignum_bitwise_op(BITWISE_OP_AND
, MP(a
), MP(b
), n
);
313 return bignum_normalize(state
, n_obj
);
316 OBJECT
bignum_or(STATE
, OBJECT a
, OBJECT b
) {
320 b
= bignum_new(state
, N2I(b
));
322 /* Perhaps this should use mp_or rather than our own version */
323 bignum_bitwise_op(BITWISE_OP_OR
, MP(a
), MP(b
), n
);
324 return bignum_normalize(state
, n_obj
);
327 OBJECT
bignum_xor(STATE
, OBJECT a
, OBJECT b
) {
331 b
= bignum_new(state
, N2I(b
));
333 /* Perhaps this should use mp_xor rather than our own version */
334 bignum_bitwise_op(BITWISE_OP_XOR
, MP(a
), MP(b
), n
);
335 return bignum_normalize(state
, n_obj
);
338 OBJECT
bignum_invert(STATE
, OBJECT self
) {
341 mp_int a
; mp_init(&a
);
342 mp_int b
; mp_init_set_int(&b
, 1);
344 /* inversion by -(a)-1 */
345 mp_neg(MP(self
), &a
);
348 mp_clear(&a
); mp_clear(&b
);
349 return bignum_normalize(state
, n_obj
);
352 OBJECT
bignum_neg(STATE
, OBJECT self
) {
356 return bignum_normalize(state
, n_obj
);
359 /* These 2 don't use mp_lshd because it shifts by internal digits,
362 OBJECT
bignum_left_shift(STATE
, OBJECT self
, OBJECT bits
) {
364 int shift
= N2I(bits
);
365 mp_int
*a
= MP(self
);
367 mp_mul_2d(a
, shift
, n
);
369 return bignum_normalize(state
, n_obj
);
372 OBJECT
bignum_right_shift(STATE
, OBJECT self
, OBJECT bits
) {
374 int shift
= N2I(bits
);
375 mp_int
* a
= MP(self
);
377 if ((shift
/ DIGIT_BIT
) >= a
->used
) {
378 if (a
->sign
== MP_ZPOS
)
387 int need_floor
= (a
->sign
== MP_NEG
) && (DIGIT(a
, 0) & 1);
389 mp_div_2d(a
, shift
, n
, NULL
);
392 /* We sometimes have to simulate the rounding toward negative
393 infinity that would happen if we were using a twos-complement
394 representation. We know we'll never overflow or need to grow,
395 but we may need to back away from zero. (libtommath doesn't
396 seem to have an increment-in-place function.) */
402 while (i
< n
->used
) {
404 DIGIT(n
,i
++) = num
& (DIGIT_RADIX
-1);
405 num
= num
>> DIGIT_BIT
;
410 return bignum_normalize(state
, n_obj
);
413 OBJECT
bignum_equal(STATE
, OBJECT a
, OBJECT b
) {
420 r
= mp_cmp_d(&n
, -N2I(b
));
423 r
= mp_cmp_d(MP(a
), N2I(b
));
426 r
= mp_cmp(MP(a
), MP(b
));
435 OBJECT
bignum_compare(STATE
, OBJECT a
, OBJECT b
) {
438 b
= bignum_new(state
, N2I(b
));
440 r
= mp_cmp(MP(a
), MP(b
));
451 OBJECT
bignum_gt(STATE
, OBJECT a
, OBJECT b
) {
455 r
= mp_cmp_d(MP(a
), (bi
= N2I(b
)) < 0 ? -bi
: bi
);
457 r
= mp_cmp(MP(a
), MP(b
));
466 OBJECT
bignum_ge(STATE
, OBJECT a
, OBJECT b
) {
470 r
= mp_cmp_d(MP(a
), -N2I(b
));
472 r
= mp_cmp_d(MP(a
), N2I(b
));
475 r
= mp_cmp(MP(a
), MP(b
));
478 if(r
== MP_GT
|| r
== MP_EQ
) {
484 OBJECT
bignum_lt(STATE
, OBJECT a
, OBJECT b
) {
488 r
= mp_cmp_d(MP(a
), (bi
= N2I(b
)) < 0 ? -bi
: bi
);
490 r
= mp_cmp(MP(a
), MP(b
));
499 OBJECT
bignum_le(STATE
, OBJECT a
, OBJECT b
) {
503 r
= mp_cmp_d(MP(a
), (bi
= N2I(b
)) < 0 ? -bi
: bi
);
505 r
= mp_cmp(MP(a
), MP(b
));
508 if(r
== MP_LT
|| r
== MP_EQ
) {
514 unsigned long bignum_to_int(STATE
, OBJECT self
) {
515 return mp_get_int(MP(self
));
518 int bignum_to_i(STATE
, OBJECT self
) {
519 mp_int
*s
= MP(self
);
521 if (s
->sign
== MP_NEG
) return -mp_get_int(s
);
523 return mp_get_int(s
);
526 unsigned int bignum_to_ui(STATE
, OBJECT self
) {
527 return (unsigned int)mp_get_int(MP(self
));
530 unsigned long long bignum_to_ull(STATE
, OBJECT self
) {
532 mp_int
*s
= MP(self
);
533 unsigned long long out
, tmp
;
535 /* mp_get_int() gets only the lower 32 bits, on any platform. */
539 mp_div_2d(s
, 32, &t
, NULL
);
541 tmp
= mp_get_int(&t
);
548 long long bignum_to_ll(STATE
, OBJECT self
) {
549 mp_int
*s
= MP(self
);
551 if (s
->sign
== MP_NEG
)
552 return -bignum_to_ull(state
, self
);
554 return bignum_to_ull(state
, self
);
557 OBJECT
bignum_from_ull(STATE
, unsigned long long val
) {
561 mp_init_set_int(&low
, val
& 0xffffffff);
562 mp_init_set_int(&high
, val
>> 32);
563 mp_mul_2d(&high
, 32, &high
);
565 ret
= bignum_new_unsigned(state
, 0);
567 mp_or(&low
, &high
, MP(ret
));
575 OBJECT
bignum_from_ll(STATE
, long long val
) {
579 ret
= bignum_from_ull(state
, (unsigned long long)-val
);
580 MP(ret
)->sign
= MP_NEG
;
582 ret
= bignum_from_ull(state
, (unsigned long long)val
);
588 OBJECT
bignum_to_s(STATE
, OBJECT self
, OBJECT radix
) {
595 buf
= ALLOC_N(char, sz
);
596 mp_toradix_nd(MP(self
), buf
, N2I(radix
), sz
, &k
);
598 obj
= string_new(state
, buf
);
607 OBJECT
bignum_from_string_detect(STATE
, char *str
) {
614 while(isspace(*s
)) { s
++; }
617 } else if(*s
== '-') {
640 mp_read_radix(n
, s
, radix
);
646 return bignum_normalize(state
, n_obj
);
649 OBJECT
bignum_from_string(STATE
, char *str
, int radix
) {
651 mp_read_radix(n
, str
, radix
);
652 return bignum_normalize(state
, n_obj
);
655 void bignum_into_string(STATE
, OBJECT self
, int radix
, char *buf
, int sz
) {
657 mp_toradix_nd(MP(self
), buf
, radix
, sz
, &k
);
660 double bignum_to_double(STATE
, OBJECT self
) {
672 /* get number of digits of the lsb we have to read */
676 /* get most significant digit of result */
680 res
= (res
* m
) + DIGIT(a
,i
);
684 /* Bignum out of range */
688 if(a
->sign
== MP_NEG
) res
= -res
;
693 OBJECT
bignum_from_double(STATE
, double d
)
701 value
= (d
< 0) ? -d
: d
;
705 rb_raise(rb_eFloatDomainError, d < 0 ? "-Infinity" : "Infinity");
708 rb_raise(rb_eFloatDomainError, "NaN");
712 while (!(value
<= (LONG_MAX
>> 1)) || 0 != (long)value
) {
713 value
= value
/ (double)(DIGIT_RADIX
);
720 value
*= DIGIT_RADIX
;
721 c
= (BDIGIT_DBL
) value
;
731 return bignum_normalize(state
, n_obj
);
734 OBJECT
bignum_size(STATE
, OBJECT self
)
736 int bits
= mp_count_bits(MP(self
));
737 int bytes
= (bits
+ 7) / 8;
739 /* MRI returns this in words, but thats an implementation detail as far
744 int bignum_hash_int(OBJECT self
)
746 mp_int
*a
= MP(self
);
748 /* Apparently, a couple bits of each a->dp[n] aren't actually used,
749 (e.g. when DIGIT_BIT is 60) so this hash is actually including
750 that unused memory. This might only be a problem if calculations
751 are leaving cruft in those unused bits. However, since Bignums
752 are immutable, this shouldn't happen to us. */
753 return string_hash_str((unsigned char *)a
->dp
, a
->used
* sizeof(mp_digit
));
756 int mp_init_set_long (mp_int
* a
, unsigned long b
)
759 if ((err
= mp_init(a
)) != MP_OKAY
) {
762 return mp_set_long(a
, b
);
765 int mp_set_long (mp_int
* a
, unsigned long b
)
768 // TODO: Move these two values to bignum.h
769 size_t count
= sizeof(unsigned long) * 2;
770 size_t shift_width
= (sizeof(unsigned long) * 8) - 4;
774 /* set four bits at a time */
775 for (x
= 0; x
< count
; x
++) {
776 /* shift the number up four bits */
777 if ((res
= mp_mul_2d (a
, 4, a
)) != MP_OKAY
) {
781 /* OR in the top four bits of the source */
782 a
->dp
[0] |= (b
>> shift_width
) & 15;
784 /* shift the source up to the next four bits */
787 /* ensure that digits are not clamped off */