RFC: should Rational accept floats?

15 views
Skip to first unread message

smichr

unread,
Nov 30, 2012, 3:32:38 PM11/30/12
to sy...@googlegroups.com
At http://code.google.com/p/sympy/issues/detail?can=2&q=2950 I give the reasons why I don't think it should.

The work is at https://github.com/sympy/sympy/pull/1680 (which disallows it).

Should we just let the user shoot themselves in the foot if they request Rational from floats or should we insist that input be integer or string?

Note: I incorrectly stated on the PR that Decimal requires int or str input. It is "unprejudiced" in accepting floats as well (as demonstrated in the python docs).

>>> Decimal(3.2)
Decimal('3.20000000000000017763568394002504646778106689453125')


But here is the problem:

>>> (3.2).as_integer_ratio()
(3602879701896397L, 1125899906842624L)
>>> Rational(*_)
3602879701896397/1125899906842624

Many would expect Rational(3.2) to give 16/5 but that's not the ratio that is represented by float 3.2. In order to get that one would have to limit the denominator:

>>> _.limit_denominator(10**15)
3199999999999997/999999999999999
>>> _.limit_denominator(10**14)
16/5

Alternatively, internally, the float could be converted to a string (which gives abaout 12 digits of precision) so Rational(3.2) would actually do

>>> Rational(str(3.2))
16/5

Thanks for any comments,
 Chris

Aaron Meurer

unread,
Nov 30, 2012, 5:23:08 PM11/30/12
to sy...@googlegroups.com
It's worth pointing out that Float does the same thing, if you give it a high enough precision. Try Float(3.2, 100) for example. 

To me, it should just work. Yes, we should encourage the use of strings over float literals, but Rational(float) not working makes it seem as if the conversion is not supported, which is not true at all. 

Aaron Meurer
--
You received this message because you are subscribed to the Google Groups "sympy" group.
To view this discussion on the web visit https://groups.google.com/d/msg/sympy/-/Ap9WvE14VdoJ.
To post to this group, send email to sy...@googlegroups.com.
To unsubscribe from this group, send email to sympy+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/sympy?hl=en.

Ronan Lamy

unread,
Dec 1, 2012, 1:32:33 AM12/1/12
to sy...@googlegroups.com
Le 30/11/2012 22:23, Aaron Meurer a �crit :
> It's worth pointing out that Float does the same thing, if you give it a
> high enough precision. Try Float(3.2, 100) for example.
>
> To me, it should just work. Yes, we should encourage the use of strings
> over float literals, but Rational(float) not working makes it seem as if
> the conversion is not supported, which is not true at all.

There are two things that bite us again and again: constructors that do
too much and polymorphic functions resulting from the conglomeration of
several simple functions under the same name. Here, both apply.

So I suggest a more radical change to the constructor: it should only
accept the two-argument form, and "rat = Rational(p, q)" should have the
following post-conditions:

assert isinstance(rat, Rational)
assert rat.p == p
assert rat.q == q

Everything else it currently does should in separate functions or
(class)methods.

Christophe BAL

unread,
Dec 1, 2012, 6:48:41 AM12/1/12
to sy...@googlegroups.com
Hello,
from mathematical point of view, the floats are a kind of approximations. So if someone
wants to have a rational form of one float, I think that it could be better that this user must
convert first the float to one decimal and then to one rational. Not user friendly but more
precise.

I don't have one concrete example, but there are situations where the approximation of a/b
will give one float, an then one decimal that when it is reconverted to one ration al p/q, this
fraction verifies p/q <> a/b.

Christophe BAL

Chris Smith

unread,
Dec 1, 2012, 7:05:01 AM12/1/12
to sy...@googlegroups.com
I'm not sure that I follow this, but for now I've not tried to guess and just use the exact n/2**e fraction that underlies all floats. This is what Decimal does (after Py 2.5) and they call it the "unprejudiced' representation of floats. 

Chris Smith

unread,
Dec 1, 2012, 7:12:57 AM12/1/12
to sy...@googlegroups.com


On Sat, Dec 1, 2012 at 12:17 PM, Ronan Lamy <ronan...@gmail.com> wrote:

Le 30/11/2012 22:23, Aaron Meurer a écrit :
It's worth pointing out that Float does the same thing, if you give it a
high enough precision. Try Float(3.2, 100) for example.

To me, it should just work. Yes, we should encourage the use of strings
over float literals, but Rational(float) not working makes it seem as if
the conversion is not supported, which is not true at all.

There are two things that bite us again and again: constructors that do too much and polymorphic functions resulting from the conglomeration of several simple functions under the same name. Here, both apply.

So I suggest a more radical change to the constructor: it should only accept the two-argument form, and "rat = Rational(p, q)" should have the following post-conditions:

assert isinstance(rat, Rational)
assert rat.p == p
assert rat.q == q


After working with this for some time now, I totally agree.  I'm not sure where this all should go. My hunch is in Number. Objects themselves have methods for getting out the underlying simple data, e.g. Decimal.as_tuple(); float.as_integer_ratio(); mpf.man_exp, and if someone is using them they should unpack the object so the receiving function doesn't have to be a polyglot. 
Reply all
Reply to author
Forward
0 new messages