Skip to content

Commit bb4a43f

Browse files
committed
py: Fix some bugs in mpz; add mpz_from_ll and mpz_set_from_ll.
A couple of bugs in mpn_shl, and overflow bug in mpz_set_from_int.
1 parent 8bfec2b commit bb4a43f

2 files changed

Lines changed: 38 additions & 5 deletions

File tree

py/mpz.c

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ STATIC int mpn_cmp(const mpz_dig_t *idig, uint ilen, const mpz_dig_t *jdig, uint
5151
STATIC uint mpn_shl(mpz_dig_t *idig, mpz_dig_t *jdig, uint jlen, uint n) {
5252
uint n_whole = (n + DIG_SIZE - 1) / DIG_SIZE;
5353
uint n_part = n % DIG_SIZE;
54+
if (n_part == 0) {
55+
n_part = DIG_SIZE;
56+
}
5457

5558
// start from the high end of the digit arrays
5659
idig += jlen + n_whole - 1;
@@ -67,7 +70,7 @@ STATIC uint mpn_shl(mpz_dig_t *idig, mpz_dig_t *jdig, uint jlen, uint n) {
6770
// store remaining bits
6871
*idig = d >> (DIG_SIZE - n_part);
6972
idig -= n_whole - 1;
70-
memset(idig, 0, n_whole - 1);
73+
memset(idig, 0, (n_whole - 1) * sizeof(mpz_dig_t));
7174

7275
// work out length of result
7376
jlen += n_whole;
@@ -412,6 +415,12 @@ mpz_t *mpz_from_int(machine_int_t val) {
412415
return z;
413416
}
414417

418+
mpz_t *mpz_from_ll(long long val) {
419+
mpz_t *z = mpz_zero();
420+
mpz_set_from_ll(z, val);
421+
return z;
422+
}
423+
415424
mpz_t *mpz_from_str(const char *str, uint len, bool neg, uint base) {
416425
mpz_t *z = mpz_zero();
417426
mpz_set_from_str(z, str, len, neg, base);
@@ -469,17 +478,38 @@ void mpz_set(mpz_t *dest, const mpz_t *src) {
469478
void mpz_set_from_int(mpz_t *z, machine_int_t val) {
470479
mpz_need_dig(z, MPZ_NUM_DIG_FOR_INT);
471480

481+
machine_uint_t uval;
472482
if (val < 0) {
473483
z->neg = 1;
474-
val = -val;
484+
uval = -val;
485+
} else {
486+
z->neg = 0;
487+
uval = val;
488+
}
489+
490+
z->len = 0;
491+
while (uval > 0) {
492+
z->dig[z->len++] = uval & DIG_MASK;
493+
uval >>= DIG_SIZE;
494+
}
495+
}
496+
497+
void mpz_set_from_ll(mpz_t *z, long long val) {
498+
mpz_need_dig(z, MPZ_NUM_DIG_FOR_LL);
499+
500+
unsigned long long uval;
501+
if (val < 0) {
502+
z->neg = 1;
503+
uval = -val;
475504
} else {
476505
z->neg = 0;
506+
uval = val;
477507
}
478508

479509
z->len = 0;
480-
while (val > 0) {
481-
z->dig[z->len++] = val & DIG_MASK;
482-
val >>= DIG_SIZE;
510+
while (uval > 0) {
511+
z->dig[z->len++] = uval & DIG_MASK;
512+
uval >>= DIG_SIZE;
483513
}
484514
}
485515

py/mpz.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ typedef struct _mpz_t {
1212

1313
#define MPZ_DIG_SIZE (15) // see mpn_div for why this needs to be at most 15
1414
#define MPZ_NUM_DIG_FOR_INT (sizeof(machine_int_t) * 8 / MPZ_DIG_SIZE + 1)
15+
#define MPZ_NUM_DIG_FOR_LL (sizeof(long long) * 8 / MPZ_DIG_SIZE + 1)
1516

1617
// convenience macro to declare an mpz with a digit array from the stack, initialised by an integer
1718
#define MPZ_CONST_INT(z, val) mpz_t z; mpz_dig_t z ## _digits[MPZ_NUM_DIG_FOR_INT]; mpz_init_fixed_from_int(&z, z_digits, MPZ_NUM_DIG_FOR_INT, val);
@@ -23,13 +24,15 @@ void mpz_deinit(mpz_t *z);
2324

2425
mpz_t *mpz_zero();
2526
mpz_t *mpz_from_int(machine_int_t i);
27+
mpz_t *mpz_from_ll(long long i);
2628
mpz_t *mpz_from_str(const char *str, uint len, bool neg, uint base);
2729
void mpz_free(mpz_t *z);
2830

2931
mpz_t *mpz_clone(const mpz_t *src);
3032

3133
void mpz_set(mpz_t *dest, const mpz_t *src);
3234
void mpz_set_from_int(mpz_t *z, machine_int_t src);
35+
void mpz_set_from_ll(mpz_t *z, long long i);
3336
uint mpz_set_from_str(mpz_t *z, const char *str, uint len, bool neg, uint base);
3437

3538
bool mpz_is_zero(const mpz_t *z);

0 commit comments

Comments
 (0)