aleaxit / gmpy

General Multi-Precision arithmetic for Python 2.6+/3+ (GMP, MPIR, MPFR, MPC)
https://gmpy2.readthedocs.io/en/latest/
GNU Lesser General Public License v3.0
519 stars 86 forks source link

Creating an mpq from Decimal no longer works #327

Closed oscarbenjamin closed 1 year ago

oscarbenjamin commented 2 years ago

I don't know if this was an intentional change but in gmpy2 2.0.8 the following code prints 1:

import gmpy2
import decimal

print(gmpy2.mpq(decimal.Decimal(1)))

However in gmpy 2.1.0 ad newer it instead gives:

$ python t.py 
Traceback (most recent call last):
  File "t.py", line 4, in <module>
    print(gmpy2.mpq(decimal.Decimal(1)))
TypeError: mpq() requires numeric or string argument

Using mpz here still works fine even if the decimal is not an integer e.g. mpz(decimal.Decimal('1.5')) gives mpz(1).

I don't have any particular use for inter-operation between Decimal and Fraction so I don't have any opinion about whether it should work. I'm just reporting this as I noticed this change and I am not sure if it is intentional. It doesn't seem to be listed in the release notes: https://gmpy2.readthedocs.io/en/latest/history.html

Decimal itself is not part of the numeric tower so I guess this change relates to gmpy2 changing to use the numeric tower.

One possibility for interacting with decimal would be the as_integer_ratio method:

In [1]: from decimal import Decimal

In [2]: d = Decimal(3)

In [3]: d.as_integer_ratio()
Out[3]: (3, 1)
boegel commented 2 years ago

This issue also surfaces in the sympy test suite, see https://github.com/sympy/sympy/issues/23061#issuecomment-1042462374

casevh commented 2 years ago

It was removed during attempts to simplify the code and decrease the overhead of argument type checking. Unfortunately, it was not well documented.

The string conversion routines for creating an 'mpq' or 'mpfr' support exponents so the following does work:

>>> mpq(str(Decimal("1.2e100")))
mpq(12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,1)
>>> mpfr(str(Decimal("1.2e100")))
mpfr('1.2000000000000001e+100')

but it doesn't work for mpz

>>> mpz(str(Decimal("1.2e100")))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid digits

There is special logic in the mpq and mpfr string conversion routines that handles exponents properly but it doesn't exist in the mpz conversion routine.

I'll look at adding the intermediate conversion of Decimal to a string to the mpq and mpfr constructors.

skirpichev commented 1 year ago

Probably, this should work if the mpq is "a replacement for Python's Fraction class", as docs says.