Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Try int<->mpz conversion with PyLong_AsNativeBytes/FromNativeBytes #517

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 43 additions & 36 deletions src/gmpy2_convert_gmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,30 +42,33 @@
static void
mpz_set_PyLong(mpz_t z, PyObject *obj)
{
int negative;
Py_ssize_t len;
PyLongObject *templong = (PyLongObject*)obj;

len = _PyLong_DigitCount(obj);
negative = _PyLong_Sign(obj) < 0;

switch (len) {
case 1:
mpz_set_si(z, (sdigit)GET_OB_DIGIT(templong)[0]);
break;
case 0:
mpz_set_si(z, 0);
break;
default:
mpz_import(z, len, -1, sizeof(digit), 0,
sizeof(digit)*8 - PyLong_SHIFT,
GET_OB_DIGIT(templong));
int overflow;
long val = PyLong_AsLongAndOverflow(obj, &overflow);

if (overflow) {
char *buf = NULL;
Py_ssize_t len = PyLong_AsNativeBytes(obj, buf, 0, -1);

buf = malloc(len);
PyLong_AsNativeBytes(obj, buf, len, -1);
mpz_import(z, len, -1, 1, 0, 0, buf);
free(buf);

int sign = 0;
PyLong_GetSign(obj, &sign);
if (sign == -1 && mpz_tstbit(z, 8*len - 1)) {
mpz_t tmp;

mpz_init(tmp);
mpz_ui_pow_ui(tmp, 256, (mp_size_t)len);
mpz_sub(z, tmp, z);
mpz_clear(tmp);
mpz_neg(z, z);
}
}

if (negative) {
mpz_neg(z, z);
else {
mpz_set_si(z, val);
}
return;
}

static MPZ_Object *
Expand Down Expand Up @@ -132,27 +135,31 @@ GMPy_PyLong_From_MPZ(MPZ_Object *obj, CTXT_Object *context)
return PyLong_FromLong(mpz_get_si(obj->z));
}

/* Assume gmp uses limbs as least as large as the builtin longs do */
mpz_t tmp, *px = &(obj->z);
int is_negative = mpz_sgn(*px) < 0;
size_t len = mpz_sizeinbase(*px, 256);
char *buf = malloc(len + 1);

size_t count, size = (mpz_sizeinbase(obj->z, 2) +
PyLong_SHIFT - 1) / PyLong_SHIFT;
PyLongObject *result;
buf[len] = 0;

if (!(result = _PyLong_New(size))) {
/* LCOV_EXCL_START */
return NULL;
/* LCOV_EXCL_STOP */
if (is_negative) {
mpz_init(tmp);
mpz_ui_pow_ui(tmp, 256, len);
mpz_add(tmp, tmp, obj->z);
px = &tmp;
buf[len] = (char) 0xff;
}

mpz_export(GET_OB_DIGIT(result), &count, -1, sizeof(digit), 0,
sizeof(digit)*8 - PyLong_SHIFT, obj->z);
len++;
mpz_export(buf, NULL, -1, 1, 0, 0, *px);

for (size_t i = count; i < size; i++) {
GET_OB_DIGIT(result)[i] = 0;
if (is_negative) {
mpz_clear(tmp);
}
_PyLong_SetSignAndDigitCount(result, mpz_sgn(obj->z) < 0, count);
PyObject *result = PyLong_FromNativeBytes(buf, len, -1);
free(buf);

return (PyObject*)result;
return result;
}

static PyObject *
Expand Down
1 change: 1 addition & 0 deletions test/test_mpz.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,7 @@ def test_mpz_create():
assert mpz(' 1 2') == mpz(12)


@settings(max_examples=10000)
@given(integers())
@example(0)
@example(-3)
Expand Down
Loading