3
/* Parroty includes. */
4
#include "parrot/parrot.h"
5
#include "parrot/extend.h"
6
#include "parrot/dynext.h"
7
#include "../6model/sixmodelobject.h"
8
#include "../6model/reprs/P6bigint.h"
10
/* The ID of the bigint REPR. */
11
static INTVAL bigint_repr_id = 0;
13
static mp_int * get_bigint(PARROT_INTERP, PMC *obj) {
14
struct SixModel_REPROps *r = REPR(obj);
15
if (r->ID == bigint_repr_id)
16
return &((P6bigintInstance *)PMC_data(obj))->body.i;
18
return &((P6bigintBody *)r->box_funcs->get_boxed_ref(interp, STABLE(obj), OBJECT_BODY(obj),
22
static FLOATVAL mp_get_double(mp_int *a) {
24
FLOATVAL sign = SIGN(a) == MP_NEG ? -1.0 : 1.0;
29
return sign * (FLOATVAL) DIGIT(a, 0);
33
d = (FLOATVAL) DIGIT(a, i);
38
d *= pow(2.0, DIGIT_BIT);
39
d += (FLOATVAL) DIGIT(a, i);
43
d *= pow(2.0, DIGIT_BIT);
44
d += (FLOATVAL) DIGIT(a, i);
47
d *= pow(2.0, DIGIT_BIT * i);
52
static void from_num(FLOATVAL d, mp_int *a) {
53
FLOATVAL d_digit = pow(2, DIGIT_BIT);
54
FLOATVAL da = fabs(d);
63
while (da > d_digit * d_digit * d_digit) {;
67
mp_grow(a, digits + 3);
69
/* populate the top 3 digits */
70
upper = da / (d_digit*d_digit);
71
rest = fmod(da, d_digit*d_digit);
72
lower = rest / d_digit;
73
lowest = fmod(rest,d_digit );
75
mp_set_long(a, (unsigned long) upper);
76
mp_mul_2d(a, DIGIT_BIT , a);
77
DIGIT(a, 0) = (mp_digit) lower;
78
mp_mul_2d(a, DIGIT_BIT , a);
81
mp_set_long(a, (unsigned long) lower);
82
mp_mul_2d(a, DIGIT_BIT , a);
88
DIGIT(a, 0) = (mp_digit) lowest;
91
mp_mul_2d(a, DIGIT_BIT * digits, a);
98
static void grow_and_negate(mp_int *a, int size, mp_int *b) {
100
int actual_size = MAX(size, USED(a));
102
mp_grow(b, actual_size);
103
USED(b) = actual_size;
104
for (i = 0; i < actual_size; i++) {
105
DIGIT(b, i) = (~DIGIT(a, i)) & MP_MASK;
111
static void two_complement_bitop(mp_int *a, mp_int *b, mp_int *c,
112
int (*mp_bitop)(mp_int *, mp_int *, mp_int *)) {
114
if (SIGN(a) ^ SIGN(b)) {
115
/* exactly one of them is negative, so need to perform
116
* some magic. tommath stores a sign bit, but Perl 6 expects
119
if (MP_NEG == SIGN(a)) {
120
grow_and_negate(a, USED(b), &d);
123
grow_and_negate(b, USED(a), &d);
126
if (DIGIT(c, USED(c) - 1) & ((mp_digit)1<<(mp_digit)(DIGIT_BIT - 1))) {
127
grow_and_negate(c, c->used, &d);
142
* The ops in here mostly just delegate off to libtommath. nqp_bigint_setup must be
143
* called before you create any types using the bigint representation.
146
inline op nqp_bigint_setup() :base_core {
147
/* Register the bigint representation. */
148
if (!bigint_repr_id) {
149
bigint_repr_id = REGISTER_DYNAMIC_REPR(interp,
150
Parrot_str_new_constant(interp, "P6bigint"),
151
P6bigint_initialize);
152
srand((unsigned int) Parrot_util_int_rand(0));
156
inline op nqp_bigint_add(out PMC, invar PMC, invar PMC, invar PMC) :base_core {
157
mp_int *a = get_bigint(interp, $2);
158
mp_int *b = get_bigint(interp, $3);
159
$1 = REPR($4)->allocate(interp, STABLE($4));
160
REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
161
mp_add(a, b, get_bigint(interp, $1));
164
inline op nqp_bigint_sub(out PMC, invar PMC, invar PMC, invar PMC) :base_core {
165
mp_int *a = get_bigint(interp, $2);
166
mp_int *b = get_bigint(interp, $3);
167
$1 = REPR($4)->allocate(interp, STABLE($4));
168
REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
169
mp_sub(a, b, get_bigint(interp, $1));
172
inline op nqp_bigint_mul(out PMC, invar PMC, invar PMC, invar PMC) :base_core {
173
mp_int *a = get_bigint(interp, $2);
174
mp_int *b = get_bigint(interp, $3);
175
$1 = REPR($4)->allocate(interp, STABLE($4));
176
REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
177
mp_mul(a, b, get_bigint(interp, $1));
180
inline op nqp_bigint_div(out PMC, invar PMC, invar PMC, invar PMC) :base_core {
181
mp_int *a = get_bigint(interp, $2);
182
mp_int *b = get_bigint(interp, $3);
184
$1 = REPR($4)->allocate(interp, STABLE($4));
185
REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
186
result = mp_div(a, b, get_bigint(interp, $1), NULL);
187
if (result == MP_VAL)
188
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
192
inline op nqp_bigint_mod(out PMC, invar PMC, invar PMC, invar PMC) :base_core {
193
mp_int *a = get_bigint(interp, $2);
194
mp_int *b = get_bigint(interp, $3);
195
$1 = REPR($4)->allocate(interp, STABLE($4));
196
REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
197
mp_mod(a, b, get_bigint(interp, $1));
200
inline op nqp_bigint_exp_mod(out PMC, invar PMC, invar PMC, invar PMC, invar PMC) :base_core {
201
mp_int *a = get_bigint(interp, $2);
202
mp_int *b = get_bigint(interp, $3);
203
mp_int *c = get_bigint(interp, $4);
204
$1 = REPR($5)->allocate(interp, STABLE($5));
205
REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
206
mp_exptmod(a, b, c, get_bigint(interp, $1));
209
inline op nqp_bigint_is_prime(out INT, invar PMC, in INT) {
210
/* mp_prime_is_prime returns True for 1, and I think
211
* it's worth special-casing this particular number :-)
213
mp_int *a = get_bigint(interp, $2);
214
if (mp_cmp_d(a, 1) == MP_EQ) {
218
mp_prime_is_prime(a, $3, (int *) &$1);
222
/* generates a pseudo random number up to $2 of type $3 */
223
inline op nqp_bigint_rand(out PMC, invar PMC, invar PMC) :base_core {
224
mp_int *a = get_bigint(interp, $2);
227
$1 = REPR($3)->allocate(interp, STABLE($3));
228
REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
230
b = get_bigint(interp, $1);
231
mp_rand(b, USED(a) + 1);
236
inline op nqp_bigint_neg(out PMC, invar PMC, invar PMC) :base_core {
237
mp_int *a = get_bigint(interp, $2);
238
$1 = REPR($3)->allocate(interp, STABLE($3));
239
REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
240
mp_neg(a, get_bigint(interp, $1));
242
inline op nqp_bigint_abs(out PMC, invar PMC, invar PMC) :base_core {
243
mp_int *a = get_bigint(interp, $2);
244
$1 = REPR($3)->allocate(interp, STABLE($3));
245
REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
246
mp_abs(a, get_bigint(interp, $1));
249
inline op nqp_bigint_cmp(out INT, invar PMC, invar PMC) :base_core {
250
mp_int *a = get_bigint(interp, $2);
251
mp_int *b = get_bigint(interp, $3);
255
inline op nqp_bigint_bool(out INT, invar PMC) :base_core {
256
$1 = !mp_iszero(get_bigint(interp, $2));
259
inline op nqp_bigint_eq(out INT, invar PMC, invar PMC) :base_core {
260
mp_int *a = get_bigint(interp, $2);
261
mp_int *b = get_bigint(interp, $3);
262
$1 = MP_EQ == mp_cmp(a, b);
265
inline op nqp_bigint_ne(out INT, invar PMC, invar PMC) :base_core {
266
mp_int *a = get_bigint(interp, $2);
267
mp_int *b = get_bigint(interp, $3);
268
$1 = MP_EQ != mp_cmp(a, b);
271
inline op nqp_bigint_gt(out INT, invar PMC, invar PMC) :base_cor {
272
mp_int *a = get_bigint(interp, $2);
273
mp_int *b = get_bigint(interp, $3);
274
$1 = MP_GT == mp_cmp(a, b);
277
inline op nqp_bigint_ge(out INT, invar PMC, invar PMC) :base_core {
278
mp_int *a = get_bigint(interp, $2);
279
mp_int *b = get_bigint(interp, $3);
280
$1 = MP_LT != mp_cmp(a, b);
283
inline op nqp_bigint_lt(out INT, invar PMC, invar PMC) :base_core {
284
mp_int *a = get_bigint(interp, $2);
285
mp_int *b = get_bigint(interp, $3);
286
$1 = MP_LT == mp_cmp(a, b);
289
inline op nqp_bigint_le(out INT, invar PMC, invar PMC) :base_core {
290
mp_int *a = get_bigint(interp, $2);
291
mp_int *b = get_bigint(interp, $3);
292
$1 = MP_GT != mp_cmp(a, b);
295
inline op nqp_bigint_gcd(out PMC, invar PMC, invar PMC, invar PMC) :base_core {
296
mp_int *a = get_bigint(interp, $2);
297
mp_int *b = get_bigint(interp, $3);
298
$1 = REPR($4)->allocate(interp, STABLE($4));
299
REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
300
mp_gcd(a, b, get_bigint(interp, $1));
303
inline op nqp_bigint_lcm(out PMC, invar PMC, invar PMC, invar PMC) :base_core {
304
mp_int *a = get_bigint(interp, $2);
305
mp_int *b = get_bigint(interp, $3);
306
$1 = REPR($4)->allocate(interp, STABLE($4));
307
REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
308
mp_lcm(a, b, get_bigint(interp, $1));
311
inline op nqp_bigint_from_str(out PMC, in STR, invar PMC) :base_core {
312
const char *buf = Parrot_str_cstring(interp, $2);
313
$1 = REPR($3)->allocate(interp, STABLE($3));
314
REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
315
mp_read_radix(get_bigint(interp, $1), buf, 10);
318
inline op nqp_bigint_to_str(out STR, invar PMC) :base_core {
319
mp_int *i = get_bigint(interp, $2);
322
mp_radix_size(i, 10, &len);
323
buf = (char *) mem_sys_allocate(len);
324
mp_toradix_n(i, buf, 10, len);
325
/* len - 1 because buf is \0-terminated */
326
$1 = Parrot_str_new(interp, buf, len - 1);
330
inline op nqp_bigint_to_str_base(out STR, invar PMC, in INT) :base_core {
331
mp_int *i = get_bigint(interp, $2);
334
mp_radix_size(i, $3, &len);
335
buf = (char *) mem_sys_allocate(len);
336
mp_toradix_n(i, buf, $3, len);
337
/* len - 1 because buf is \0-terminated */
338
$1 = Parrot_str_new(interp, buf, len - 1);
342
inline op nqp_bigint_to_num(out NUM, invar PMC) :base_core {
343
mp_int *a = get_bigint(interp, $2);
344
$1 = mp_get_double(a);
347
inline op nqp_bigint_from_num(out PMC, in NUM, invar PMC) :base_core {
348
$1 = REPR($3)->allocate(interp, STABLE($3));
349
REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
350
from_num($2, get_bigint(interp, $1));
353
inline op nqp_bigint_div_num(out NUM, invar PMC, invar PMC) :base_core {
354
mp_int *a = get_bigint(interp, $2);
355
mp_int *b = get_bigint(interp, $3);
357
int max_size = DIGIT_BIT * MAX(USED(a), USED(b));
358
if (max_size > 1023) {
359
mp_int reduced_a, reduced_b;
362
mp_div_2d(a, max_size - 1023, &reduced_a, NULL);
363
mp_div_2d(b, max_size - 1023, &reduced_b, NULL);
364
$1 = mp_get_double(&reduced_a) / mp_get_double(&reduced_b);
365
mp_clear(&reduced_a);
366
mp_clear(&reduced_b);
368
$1 = mp_get_double(a) / mp_get_double(b);
372
inline op nqp_bigint_shr(out PMC, invar PMC, in INT, invar PMC) :base_core {
373
mp_int *a = get_bigint(interp, $2);
374
$1 = REPR($4)->allocate(interp, STABLE($4));
375
REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
376
mp_div_2d(a, $3, get_bigint(interp, $1), NULL);
379
inline op nqp_bigint_shl(out PMC, invar PMC, in INT, invar PMC) :base_core {
381
mp_int *a = get_bigint(interp, $2);
382
$1 = REPR($4)->allocate(interp, STABLE($4));
383
REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
384
b = get_bigint(interp, $1);
388
inline op nqp_bigint_band(out PMC, invar PMC, invar PMC, invar PMC) :base_core {
389
mp_int *a = get_bigint(interp, $2);
390
mp_int *b = get_bigint(interp, $3);
391
$1 = REPR($4)->allocate(interp, STABLE($4));
392
REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
393
two_complement_bitop(a, b, get_bigint(interp, $1), mp_and);
395
inline op nqp_bigint_bor(out PMC, invar PMC, invar PMC, invar PMC) :base_core {
396
mp_int *a = get_bigint(interp, $2);
397
mp_int *b = get_bigint(interp, $3);
398
$1 = REPR($4)->allocate(interp, STABLE($4));
399
REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
400
two_complement_bitop(a, b, get_bigint(interp, $1), mp_or);
402
inline op nqp_bigint_bxor(out PMC, invar PMC, invar PMC, invar PMC) :base_core {
403
mp_int *a = get_bigint(interp, $2);
404
mp_int *b = get_bigint(interp, $3);
405
$1 = REPR($4)->allocate(interp, STABLE($4));
406
REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
407
two_complement_bitop(a, b, get_bigint(interp, $1), mp_xor);
409
inline op nqp_bigint_bnot(out PMC, invar PMC, invar PMC) :base_core {
410
mp_int *a = get_bigint(interp, $2);
412
$1 = REPR($3)->allocate(interp, STABLE($3));
413
REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
414
b = get_bigint(interp, $1);
416
/* 2s complement: add 1, negate */
424
=item nqp_bigint_radix(out, radix, str, pos, flag, type)
426
Convert string $3 into a number starting at offset $4 and using radix $2.
427
The result of the conversion returns a FixedPMCArray of size 3 with objects
428
of type $6, which is either a bigint or some type that boxes one.
430
The contents of $6 are the return value, the base to divide the value by if
431
it is something after a decimal dot, and the new position.
433
The $5 flags is a bitmask that modifies the parse and/or result:
434
0x01: negate the result (useful if you've already parsed a minus)
435
0x02: parse a leading +/- and negate the result on -
436
0x04: parse trailing zeroes but do not include in result
437
(for parsing values after a decimal point)
443
inline op nqp_bigint_radix(out PMC, in INT, in STR, in INT, in INT, invar PMC) :base_core {
449
INTVAL chars = Parrot_str_length(interp, str);
462
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
463
"Cannot convert radix of %d (max 36)", radix);
468
mp_set_int(&zbase, 1);
470
value_obj = REPR($6)->allocate(interp, STABLE($6));
471
REPR(value_obj)->initialize(interp, STABLE(value_obj), OBJECT_BODY(value_obj));
472
value = get_bigint(interp, value_obj);
474
base_obj = REPR($6)->allocate(interp, STABLE($6));
475
REPR(base_obj)->initialize(interp, STABLE(base_obj), OBJECT_BODY(base_obj));
476
base = get_bigint(interp, base_obj);
479
ch = (zpos < chars) ? STRING_ord(interp, str, zpos) : 0;
480
if ((flags & 0x02) && (ch == '+' || ch == '-')) {
483
ch = (zpos < chars) ? STRING_ord(interp, str, zpos) : 0;
485
while (zpos < chars) {
486
if (ch >= '0' && ch <= '9') ch = ch - '0';
487
else if (ch >= 'a' && ch <= 'z') ch = ch - 'a' + 10;
488
else if (ch >= 'A' && ch <= 'Z') ch = ch - 'A' + 10;
490
if (ch >= radix) break;
491
mp_mul_d(&zvalue, radix, &zvalue);
492
mp_add_d(&zvalue, ch, &zvalue);
493
mp_mul_d(&zbase, radix, &zbase);
495
if (ch != 0 || !(flags & 0x04)) { mp_copy(&zvalue, value); mp_copy(&zbase, base); }
496
if (zpos >= chars) break;
497
ch = STRING_ord(interp, str, zpos);
498
if (ch != '_') continue;
500
if (zpos >= chars) break;
501
ch = STRING_ord(interp, str, zpos);
507
pos_obj = REPR($6)->allocate(interp, STABLE($6));
508
REPR(pos_obj)->initialize(interp, STABLE(pos_obj), OBJECT_BODY(pos_obj));
509
REPR(pos_obj)->box_funcs->set_int(interp, STABLE(pos_obj), OBJECT_BODY(pos_obj), pos);
511
if (neg || flags & 0x01) { mp_neg(value, value); }
512
out = Parrot_pmc_new(interp, enum_class_FixedPMCArray);
513
VTABLE_set_integer_native(interp, out, 3);
514
VTABLE_set_pmc_keyed_int(interp, out, 0, value_obj);
515
VTABLE_set_pmc_keyed_int(interp, out, 1, base_obj);
516
VTABLE_set_pmc_keyed_int(interp, out, 2, pos_obj);
520
/* calculates $1 = $2 ** $3
521
* if it either overflows ($3 being too big), or $2 is negative,
522
* a float is returned. $4 should contain the type object to box the
523
* float into, $5 the type object to box the bigint into.
525
inline op nqp_bigint_pow(out PMC, invar PMC, invar PMC, invar PMC, invar PMC) :base_core {
526
mp_digit exponent_d = 0;
527
mp_int *exponent = get_bigint(interp, $3);
528
mp_int *base = get_bigint(interp, $2);
529
int cmp = mp_cmp_d(exponent, 0);
530
if (cmp == MP_EQ || MP_EQ == mp_cmp_d(base, 1)) {
531
/* $x ** 0 or 1 ** $x */
532
$1 = REPR($5)->allocate(interp, STABLE($5));
533
REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
534
mp_set_int(get_bigint(interp, $1), 1);
536
else if (cmp == MP_GT) {
537
exponent_d = mp_get_int(exponent);
538
if (MP_GT == mp_cmp_d(exponent, exponent_d)) {
539
/* the exponent is larger than what fits into an int register...
540
* that's scary, and should be treated with care */
543
/* XXX a bit ugly that it reuses cmp, but safe for now */
544
cmp = mp_cmp_d(base, 0);
545
if (MP_EQ == cmp || MP_EQ == mp_cmp_d(base, 1)) {
546
/* 0 ** $big_number and 1 ** big_number are easy to do: */
547
$1 = REPR($2)->allocate(interp, STABLE($2));
548
REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
549
mp_copy(base, get_bigint(interp, $1));
553
$1 = REPR($4)->allocate(interp, STABLE($4));
554
REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
555
/* TODO: better ways to create +- Inf */
557
REPR($1)->box_funcs->set_num(interp, STABLE($1), OBJECT_BODY($1), (FLOATVAL) 1.0/ZERO);
560
REPR($1)->box_funcs->set_num(interp, STABLE($1), OBJECT_BODY($1), (FLOATVAL) -1.0/ZERO);
565
/* since the exponent fits into a digit, mp_expt_d is fine */
566
$1 = REPR($5)->allocate(interp, STABLE($5));
567
REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
568
mp_expt_d(get_bigint(interp, $2), exponent_d, get_bigint(interp, $1));
572
FLOATVAL f_base = mp_get_double(base);
573
FLOATVAL f_exp = mp_get_double(exponent);
574
$1 = REPR($4)->allocate(interp, STABLE($4));
575
REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
576
REPR($1)->box_funcs->set_num(interp, STABLE($1), OBJECT_BODY($1), pow(f_base, f_exp));
580
/* returns 1 if $2 is too large to fit into an INTVAL without loss of
582
inline op nqp_bigint_is_big(out INT, invar PMC) :base_core {
583
mp_int *a = get_bigint(interp, $2);
585
/* XXX somebody please check that on a 32 bit platform */
586
if ( sizeof(INTVAL) * 8 < DIGIT_BIT && $1 == 0 && DIGIT(a, 0) & ~0x7FFFFFFFUL)