[Edu-sig] Re: Still working on rational numbers PEP?
Kirby Urner
urnerk@qwest.net
Mon, 30 Sep 2002 12:14:20 -0700
============
"Christopher A. Craig" <ccraig@ccraig.org> wrote:
I think your problem is in assuming that Python 3 division will return
a float. The plan for Python 3 is that the / operator will return "a
reasonable approximation to the mathematical result of division."[1] The
reason it is presently slated to return a float is that there is no
rational in Python. Guido has even stated [2]
By the time 3.0 comes around, (1L<<2000)/1 will probably return a
rational number. But until we have added rationals, I think that for
most apps, long/long -> float is the only definition that is
consistent with the other requirements...
So if rationals go in before 3.0, 1/2 may be the rational one-half and
not the float 0.5. Changing the behaviour of the divide operator is
going to break a bunch of code regardless of whether the new code
returns a float or a rational, but that breakage is already scheduled
to happen.
> >>> a = 1r2 + 1r2
> >>> a
> 1
> >>> 1/a
> 1
> >>> a/3
> 1r3
>
> If you have the time, please show me how you would express the
> above using your proposed extensions.
>
>>> 1/2
1/2
>>> a = 1/2 + 1/2
>>> a
1
>>> 1/a
1
>>> a/3
1/3
>====================================================================
Kirby:
I think there's an option to be less radical and break less pre-
existing code. According to the above scenario, code rewritten to
accommodate 1/2 == 0.5 as per recent changes, will have to be
rewritten *again*.
I would prefer to see / return a rational if and only both
arguments are rational. Otherwise it should return a float,
as per the current plan.
Rational arithmetic is in general rather expensive, and the
expectation the 4/17 will take us into floating point territory
is entirely reasonable I think. Only if 4 and 17 are both
type rational would 4/17 then not return a type float answer.
So I would prefer we keep the option to go:
>>> 5e_1
0.5
>>> 1r2
1r2
on the table. Maybe I will subscribe to python-dev and try to
at least prompt a little worthwhile discussion of the proposal,
recognizing that it may well be dismissed. Or you could do
a quick blurb on "what Kirby thinks". In the meantime, I'm
CC-ing this to edu-sig, where this thread got started (for me).
I thank you for you patience in bringing me up to speed on the
current proposal.
Given we're in the initial stages of this and a lot of Pythonistas
may not be aware of the J language option, which is quite viable,
I think it should at least be looked at.
In J, the division operator is % (because / means something else).
So in J, a conversation might go like this:
1%2 NB. i.e. 1/2 -- same as Python 2.3
0.5
1r2
1r2
1r2 + 1r3
5r6
1%2 + 1%3
0.428571
The last line above is a surprise -- because J (unlike Python)
has no concept of operator precedence (Python should stay the
way it is of course). 1%2 + 1%3 really means (in Python)
1/(2 + (1/3)). To get more what we'd expect, we go:
(1%2) + (1%3)
0.833333
(x:0.5555) % 1r2 NB. x: coerces 0.5555 to be rational
1111r1000
In Python, we might go:
>>> rat(0.5555)
1111r2000
>>> rat(0.5555)/1r2
1111r1000
The main objection to my proposal, I think, is that it seems
to return us to the bad old days (like now), when / can do
different things depending on the types of the operands. But
of course that's true with many operands. float + float is
float, int + int is int. The objection, specifically in the
case of division, is you "lose information" by returning 0 in
place of 0.5 (depending on whether this is int/int or float/float)
-- these are NOT "reasonably equivalent" answers.
In contrast, returning a rational type would be to return the
*fractional equivalent* of a float, i.e. the results are arguably
the same, within tolerance. Just as 1.0 == 1, so 1r2 == 0.5 == 5e_1.
so no information is lost, perhaps conforming to Guido's long term
intentions for / (of course I don't speak for Guido in any way
-- maybe I'm way off base here).
In J, when you coerce pi to a rational, you get:
1285290289249r409120605684 which in floating point is
3.1415926535896439. That's not *quite* the same as
>>> math.pi
3.1415926535897931
but in Python we'd be free to go to more decimal places using
longs in both numerator and denominator -- if we want (could do
that in J to -- I'll have to ask why they didn't).
Kirby