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

Misc fixes #499

Merged
merged 4 commits into from
Jul 26, 2024
Merged
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
2 changes: 1 addition & 1 deletion docs/contexts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ that contexts are mutable: modifying the reference returned by `get_context()`
will modify the active context until a new context is enabled with
`set_context()`. The `context.copy()` method will return a copy of the
context. Contexts that implement the standard *single*, *double*, and
*quadruple* precision floating point types can be created using `ieee()`.
*quadruple* precision floating-point types can be created using `ieee()`.

Context Type
------------
Expand Down
2 changes: 1 addition & 1 deletion docs/history.rst
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ Changes in gmpy2 2.1.0a1
* Context methods have been added for MPFR/MPC related functions.
* A new context option (`~context.rational_division`) has been added that
changes the behavior of integer division involving `mpz` instances to return
a rational result instead of a floating point result.
a rational result instead of a floating-point result.
* gmpy2 types are now registered in the numeric tower of the
:mod:`numbers` module.
* In previous versions of gmpy2, ``mpz()`` was a factory function that
Expand Down
6 changes: 3 additions & 3 deletions src/gmpy2_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ GMPy_CTXT_Exit(PyObject *self, PyObject *args)

PyDoc_STRVAR(GMPy_doc_context_ieee,
"ieee(size, /, subnormalize=True) -> context\n\n"
"Return a new context corresponding to a standard IEEE floating point\n"
"Return a new context corresponding to a standard IEEE floating-point\n"
"format. The supported sizes are 16, 32, 64, 128, and multiples of\n"
"32 greater than 128.");

Expand Down Expand Up @@ -706,10 +706,10 @@ GETSET_BOOLEAN(rational_division)
GETSET_BOOLEAN(allow_release_gil)

PyDoc_STRVAR(GMPy_doc_CTXT_subnormalize,
"The usual IEEE-754 floating point representation supports gradual\n"
"The usual IEEE-754 floating-point representation supports gradual\n"
"underflow when the minimum exponent is reached. The MFPR library\n"
"does not enable gradual underflow by default but it can be enabled\n"
"to precisely mimic the results of IEEE-754 floating point operations.");
"to precisely mimic the results of IEEE-754 floating-point operations.");

PyDoc_STRVAR(GMPy_doc_CTXT_trap_underflow,
"If set to `False`, a result that is smaller than the smallest possible\n"
Expand Down
19 changes: 14 additions & 5 deletions src/gmpy2_convert_gmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -789,16 +789,25 @@ GMPy_PyStr_From_MPQ(MPQ_Object *obj, int base, int option, CTXT_Object *context)
static PyObject *
GMPy_PyFloat_From_MPQ(MPQ_Object *obj, CTXT_Object *context)
{
double res;
MPFR_Object *tmp;

res = mpq_get_d(obj->q);
CHECK_CONTEXT(context);

if (isinf(res)) {
OVERFLOW_ERROR("'mpq' too large to convert to float");
if (!(tmp = GMPy_MPFR_New(53, context))) {
/* LCOV_EXCL_START */
return NULL;
/* LCOV_EXCL_STOP */
}

return PyFloat_FromDouble(res);
mpfr_clear_flags();
tmp->rc = mpfr_set_q(tmp->f, obj->q, MPFR_RNDN);
GMPY_MPFR_CHECK_RANGE(tmp, context);
GMPY_MPFR_SUBNORMALIZE(tmp, context);
GMPY_MPFR_EXCEPTIONS(tmp, context);

PyObject *res = GMPy_PyFloat_From_MPFR(tmp, context);
Py_DECREF(tmp);
return res;
}

static PyObject *
Expand Down
2 changes: 1 addition & 1 deletion src/gmpy2_convert_mpfr.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
* If bits (or prec) is set to 1, the precision of the result depends on the
* type of the source.
*
* If the source number is already a radix-2 floating point number,
* If the source number is already a radix-2 floating-point number,
* the precision is not changed. In practical terms, this only applies
* to sources operands that are either an mpfr or Python double.
*
Expand Down
4 changes: 3 additions & 1 deletion src/gmpy2_macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,9 @@ GMPy_RealWithType_##NAME(PyObject *x, int xtype, CTXT_Object *context) \
result->rc = mpfr_##FUNC(result->f, tempx->f); \
Py_DECREF((PyObject*)tempx); \
_GMPy_MPFR_Cleanup(&result, context); \
return (PyObject*)result; \
MPZ_Object *mpz_result = GMPy_MPZ_From_MPFR(result, context); \
Py_DECREF((PyObject*)result); \
return (PyObject*)mpz_result; \
} \
static PyObject * \
GMPy_Number_##NAME(PyObject *x, CTXT_Object *context) \
Expand Down
2 changes: 1 addition & 1 deletion src/gmpy2_mpfr.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ PyDoc_STRVAR(GMPy_doc_mpfr,
"the specified context or the current context is used.\n"
"A precision of 1 minimizes the loss of precision by following\n"
"these rules:\n\n"
" 1) If n is a radix-2 floating point number, then the full\n"
" 1) If n is a radix-2 floating-point number, then the full\n"
" precision of n is retained.\n"
" 2) If n is an integer, then the precision is the bit length\n"
" of the integer.\n");
Expand Down
3 changes: 3 additions & 0 deletions src/gmpy2_mpmath.c
Original file line number Diff line number Diff line change
Expand Up @@ -287,14 +287,17 @@ Pympz_mpmath_create_fast(PyObject *self, PyObject *const *args, Py_ssize_t nargs
switch (nargs) {
case 4:
rnd = PyString_1Char(args[3]);
/* fallthrough */
case 3:
prec = GMPy_Integer_AsLong(args[2]);
if (prec == (mp_bitcnt_t)(-1)) {
VALUE_ERROR("could not convert prec to positive int");
return NULL;
}
/* fallthrough */
case 2:
exp = args[1];
/* fallthrough */
case 1:
man = GMPy_MPZ_From_Integer(args[0], NULL);
if (!man) {
Expand Down
37 changes: 36 additions & 1 deletion test/test_mpfr.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import pytest
from hypothesis import example, given, settings
from hypothesis.strategies import floats
from hypothesis.strategies import floats, integers
from supportclasses import a, b, c, d, q, r, z

import gmpy2
Expand Down Expand Up @@ -872,3 +872,38 @@ def test_mpfr_pickle():
assert pickle.loads(pickle.dumps(mpfr("-inf"))) == mpfr('-inf')
assert is_nan(pickle.loads(pickle.dumps(mpfr("nan"))))
assert pickle.loads(pickle.dumps(mpfr(0))) == mpfr('0.0')


def test_mpfr_floor():
a = mpfr('12.34')

ctx = get_context()
r = ctx.floor(a)

assert r == mpz(12) and isinstance(r, mpz)


def test_mpfr_ceil():
a = mpfr('12.34')

ctx = get_context()
r = ctx.ceil(a)

assert r == mpz(13) and isinstance(r, mpz)


def test_mpfr_trunc():
a = mpfr('12.34')

ctx = get_context()
r = ctx.trunc(a)

assert r == mpz(12) and isinstance(r, mpz)


@given(floats(allow_nan=False, allow_infinity=False),
integers(-10, 40))
def test_mpfr_round_roundtrip_bulk(x, n):
q = mpq(*x.as_integer_ratio())
assert float(round(q, n)) == round(x, n)
assert mpfr(round(q, n)) == round(mpfr(x), n)
4 changes: 4 additions & 0 deletions test/test_mpq.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ def test_mpq_from_float():
assert mpq.from_float(3.2) == mpq(3602879701896397, 1125899906842624)


def test_mpq_float():
assert float(mpq(9, 5)) == 1.8


def test_mpq_from_Decimal():
assert mpq(Decimal("5e-3")) == mpq(5, 1000)
assert mpq(Decimal(1)) == mpq(1) # issue 327
Expand Down
Loading