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

Implicitly converting floats to Rational in SymPy APIs #15844

Open
oscarbenjamin opened this issue Jan 25, 2019 · 5 comments
Open

Implicitly converting floats to Rational in SymPy APIs #15844

oscarbenjamin opened this issue Jan 25, 2019 · 5 comments
Labels

Comments

@oscarbenjamin
Copy link
Contributor

Does SymPy have any policy on implicit conversion of float to Rational at API entry points?

It seems to me like there are many functions that work a lot better if you pass in Rationals even for simple numbers like 0.1. I would consider that important advice to users: pass in exact inputs where possible.

On the other hand there are lots of users who really want to be able to write 0.1 instead of S(1)/10 etc and have SymPy treat it the same. I see this come up often in issues/questions so I think the current behaviour breaks common user expectations.

OTOH I might prefer 0.1 to be treated as exactly S('0.1000000000000000055511151231257827021181583404541015625') but I suspect I would be in the minority among users.

I'm asking this because Point auto-converts float to Rational (inexactly using nsimplify). Circle passes some arguments to Point but keeps the radius itself so

In [38]: Circle([0.1,0.1],0.1)                                                                                                                 
Out[38]: Circle(Point2D(1/10, 1/10), 0.100000000000000)

The fix proposed in #15816 is to convert the radius as well but actually I wonder if the mistake is the fact that Point does auto-conversion.

This then leads on to questions like what should is_tangent do in the presence of floats. Normally a floating point routine for a question like that would be based on some tolerance return abs(dist) < tol. Maybe the answer should be put back to users: don't use floats or don't use functions like is_tangent with floats etc.

See also #11484.

@oscargus
Copy link
Contributor

What about having a method (maybe that method is nsimplify, I do not know), which can guess what a floating point number really is and that is easy/short enough for the users to apply frequently? For example, 3.141593 will be good enough to convert to pi. I think that there is something similar in at least Maple.

Very relevant question though!

Also, I think that it can be OK to convert 0.1 to 1/10 given that there is a way to get and use the "exact" floating-point representation. Despite being a minority of users, there are some that would like that to happen. Despite being a generally evil idea, can one have two global modes? One where it is OK to convert things like that, maybe default, one where it isn't?

@asmeurer
Copy link
Member

solve has a rational flag which has been quite contentious in the past.

What about having a method (maybe that method is nsimplify, I do not know), which can guess what a floating point number really is and that is easy/short enough for the users to apply frequently?

There is already some code that does this (yes, from nsimplify), but it is bad IMO. It leads to a lot of problems. See #12045. Also see #12534 and the dozens of linked issues if you want to get a better handle on this stuff.

There is no way for SymPy to distinguish between 0.1, 1/10, and 3602879701896397/36028797018963968. They all produce the exact same floating point number.

On the other hand, treating floats as equal to things that they are only approximately equal to can lead to a lot of issues (#11707).

@sylee957
Copy link
Member

I also think that overdetermination can make the system too much sensitive and make too much undecidable cases.

Once some digits of an expression are floating numbers, I don't think there should be theoritical accuracy to be concerned because a same floating number can be arrived in many ways, from rational and irrational numbers truncated, to aggrevated errors due to multiplications.

I think sympy supports floating points and exact numbers unevaluated in a single expression like

But in Mathematica, I think they are automatically absorbed by floating points

and numerical approximation routines are being used once any floating number is found inside the expression.

@asmeurer
Copy link
Member

0.3*sqrt(3) is left unevaluated only because it could be too expensive in general to evaluate the rest of the expression in a Mul. Imagine it was 0.3*some_large_expression. And in practice evalf can be slow, especially on things like Sum or Integral.

Function calls like sqrt or sin will evaluate on floats because that only requires evaluating the function on one float.

@smichr
Copy link
Member

smichr commented May 29, 2019

OTOH I might prefer 0.1 to be treated as exactly [as high-precision fraction]

This can be handled at instantiation with Rational(.1) vs Rational(str(.1))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants