@@ -318,3 +318,64 @@ inline op nqp_bigint_radix(out PMC, in INT, in STR, in INT, in INT, in PMC) :bas
318
318
VTABLE_set_pmc_keyed_int(interp, out, 2, pos_obj);
319
319
$1 = out;
320
320
}
321
+
322
+ /* calculates $1 = $2 ** $3
323
+ * if it either overflows ($3 being too big), or $2 is negative,
324
+ * a float is returned. $4 should contain the type object to box the
325
+ * float into.
326
+ */
327
+ inline op nqp_bigint_pow(out PMC, in PMC, in PMC, in PMC) :base_core {
328
+ mp_digit exponent_d = 0;
329
+ mp_int *exponent = get_bigint(interp, $3);
330
+ mp_int *base = get_bigint(interp, $2);
331
+ int cmp = mp_cmp_d(exponent, 0);
332
+ if (cmp == MP_EQ || MP_EQ == mp_cmp_d(base, 1)) {
333
+ /* $x ** 0 or 1 ** $x */
334
+ $1 = REPR($2)->allocate(interp, STABLE($2));
335
+ REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
336
+ mp_set_int(get_bigint(interp, $1), 1);
337
+ }
338
+ else if (cmp == MP_GT) {
339
+ exponent_d = mp_get_int(exponent);
340
+ if (MP_GT == mp_cmp_d(exponent, exponent_d)) {
341
+ /* the exponent is larger than what fits into an int register...
342
+ * that's scary, and should be treated with care */
343
+
344
+
345
+ /* XXX a bit ugly that it reuses cmp, but safe for now */
346
+ cmp = mp_cmp_d(base, 0)
347
+ if (MP_EQ == cmp || MP_EQ == mp_cmp_d(base, 1)) {
348
+ /* 0 ** $big_number and 1 ** big_number are easy to do: */
349
+ $1 = REPR($2)->allocate(interp, STABLE($2));
350
+ REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
351
+ mp_copy(base, get_bigint(interp, $1));
352
+ }
353
+ else {
354
+ $1 = REPR($4)->allocate(interp, STABLE($4));
355
+ REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
356
+ /* TODO: better ways to create +- Inf */
357
+ if (MP_GT == cmp) {
358
+ REPR($1)->set_num(interp, STABLE($1), OBJECT_BODY($1), (FLOATVAL) 1.0/0.0);
359
+ }
360
+ else {
361
+ REPR($1)->set_num(interp, STABLE($1), OBJECT_BODY($1), (FLOATVAL) -1.0/0.0);
362
+ }
363
+ }
364
+ }
365
+ else {
366
+ /* since the exponent fits into a digit, mp_expt_d is fine */
367
+ $1 = REPR($2)->allocate(interp, STABLE($2));
368
+ REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
369
+ mp_expt_d(get_bigint(interp, $2), exponent_d, get_bigint(interp, $1));
370
+ }
371
+ }
372
+ else {
373
+ /* TODO: better way to get floats out of mp_int */
374
+ FLOATVAL f_base = (FLOATVAL) REPR($2)->get_int(interp, STABLE($2), OBJECT_BODY($2));
375
+ FLOATVAL f_exp = (FLOATVAL) REPR($3)->get_int(interp, STABLE($3), OBJECT_BODY($3));
376
+ $1 = REPR($4)->allocate(interp, STABLE($4));
377
+ REPR($1)->initialize(interp, STABLE($1), OBJECT_BODY($1));
378
+ REPR($1)->set_num(interp, STABLE($1), OBJECT_BODY($1), pow(f_base, f_exp));
379
+ }
380
+ }
381
+
0 commit comments