Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

PEP239 (Rational Numbers) Reference Implementation and new issues

0 views
Skip to first unread message

pytho...@ccraig.org

unread,
Oct 2, 2002, 6:11:41 PM10/2/02
to
I just uploaded a reference implementation of how rationals might look
in Python as patch 617779 [1]. I do have some new issues for
discussion that I'd like to get some comments on before I change the
PEP.

1) Should future division return rationals rather than floats. I had
sort of assumed this would happen, but I just had a discussion with
Kirby Urner and couldn't convince him it was a good idea, so I guess
it isn't so clear.

Arguments for:
- you don't lose precision on divides
- It provides a really nice way to specify rationals (i.e. 1/3)
- It allows you to eventually unify int/long/rationals so that
rationals with a denominator of 1 are automagically upcast.

Arguments against:
- people who have already changed their code to expect floats will
have to change it again
- rationals are slow

2) Should floats compare equal with rationals only when they are
equal, or whenever the are the closest float? (i.e. will .2
compare equal to rational(1, 5))

3) Should rationals try to hash the same as floats? My leaning on
this is that it will be decided by (2). If they compare equal when
'close enough' then they should hash the same, if not then they should
only hash the same when both are integral. I would rather not see .5
hash with rational(1, 2) but not .2 with rational(1, 5).

[1] http://sourceforge.net/tracker/?func=detail&aid=617779&group_id=5470&atid=305470

--
Christopher A. Craig <pytho...@ccraig.org>
"[Windows NT is] not about 'Where do you want to go today?'; it's more like
'Where am I allowed to go today?'" -- Mike Mitchell, NT Systems Administrator

François Pinard

unread,
Oct 2, 2002, 6:56:49 PM10/2/02
to
[Eric S. Raymond]

>> 1) Should future division return rationals rather than floats.

> +1 for returning rationals. It's the right thing -- and if it fails,
> it will fail noisily, right?

While I agree with the theoretical arguments, I have the practical fear that
rationals could grow very big, rather quickly, in the course of a long
computation involving them in various ways. By big, I mean the numerator
and denominator of the fraction taken in isolation, not the number itself.
Consider inversions of an integer matrices, approximations with truncated
series, or worse things like, maybe, discrete Fourier transforms.

Bigger rationals are, slower they become, and more memory they take. The
danger is that programmers may get surprised or hurt by Python performance
degradation, raising frequent and recurrent questions here and elsewhere.

On the other hand, I would love if Python was not loosing precision on
non-truncating integer division, so let me try a bit to destroy my own
fears. On average, most programs will not use matrices of rational numbers,
nor play with series. Moreover, most programs do not use so many different
numeric variables anyway, nor perform long computations involving them.
Many programs do not go beyond adding or subtracting one, once in a while!

So, I would guess that _on the average_, using rational numbers might be
acceptable and go almost unnoticed by most people. So it might be more
worth accepting as a community to warn programmers who are more prone to
numerical algorithms of the intrinsic dangers of integer division in Python.

But those feelings are no proof of anything. How do we get the confirmation
that using rationals in Python would be easy going and innocuous in
practice, beforehand? It would surely be nice relying in such a feature!

--
François Pinard http://www.iro.umontreal.ca/~pinard


Paul Rubin

unread,
Oct 2, 2002, 7:20:35 PM10/2/02
to
pytho...@ccraig.org writes:
> 1) Should future division return rationals rather than floats. I had
> sort of assumed this would happen, but I just had a discussion with
> Kirby Urner and couldn't convince him it was a good idea, so I guess
> it isn't so clear.

No--on the theory that 3/2 == 1.5 in future division for the benefit
of newbies who get confused by 3/2 == 1 as we're used to from int
arithmetic. Future division returns floats because that's what
non-programmers are used to from BASIC and spreadsheets. They
don't expect rationals, so rationals aren't the right thing.

> 2) Should floats compare equal with rationals only when they are
> equal, or whenever the are the closest float? (i.e. will .2
> compare equal to rational(1, 5))
>
> 3) Should rationals try to hash the same as floats? My leaning on
> this is that it will be decided by (2). If they compare equal when
> 'close enough' then they should hash the same, if not then they should
> only hash the same when both are integral. I would rather not see .5
> hash with rational(1, 2) but not .2 with rational(1, 5).

Unless there's a good reason to do something different, follow existing
standards, e.g. do what Scheme or Common Lisp does in these situations.

Christian Tismer

unread,
Oct 2, 2002, 7:13:57 PM10/2/02
to
François Pinard wrote:
> [Eric S. Raymond]

>
>
>>>1) Should future division return rationals rather than floats.
>>
>
>>+1 for returning rationals. It's the right thing -- and if it fails,
>>it will fail noisily, right?

+1 here, too!

> While I agree with the theoretical arguments, I have the practical fear that
> rationals could grow very big, rather quickly, in the course of a long
> computation involving them in various ways. By big, I mean the numerator
> and denominator of the fraction taken in isolation, not the number itself.
> Consider inversions of an integer matrices, approximations with truncated
> series, or worse things like, maybe, discrete Fourier transforms.

Yes, this fear is right.
I think this is just great. Let it grow! Let the user feel what
precision he's carrying around, and how much they throw away
when they reduce down to float.

No I think this is really of advantage. Exact is better than small,
and it is all in the user's hand. Make a float() and you're done.

> Bigger rationals are, slower they become, and more memory they take. The
> danger is that programmers may get surprised or hurt by Python performance
> degradation, raising frequent and recurrent questions here and elsewhere.
>
> On the other hand, I would love if Python was not loosing precision on
> non-truncating integer division, so let me try a bit to destroy my own
> fears. On average, most programs will not use matrices of rational numbers,
> nor play with series. Moreover, most programs do not use so many different
> numeric variables anyway, nor perform long computations involving them.
> Many programs do not go beyond adding or subtracting one, once in a while!

I don't think one was considering to go rationale, all the time,
just as the result of integer divide? To me, rationales would be
the natural superclass of integers.
Floats would stand somewhere else, really different animals.

> So, I would guess that _on the average_, using rational numbers might be
> acceptable and go almost unnoticed by most people. So it might be more
> worth accepting as a community to warn programmers who are more prone to
> numerical algorithms of the intrinsic dangers of integer division in Python.
>
> But those feelings are no proof of anything. How do we get the confirmation
> that using rationals in Python would be easy going and innocuous in
> practice, beforehand? It would surely be nice relying in such a feature!

I'm all for it. Get correct results in the first place.
Cut precision explicitly when needed, or for optimization.

BTW., Mathematica did the same thing. Very handy if you are doing
symbolic operations on polynomials, and you can easily keep
exact coefficients for a long time.
Another point is that a long division would never give an overflow.
Overflow since floats are too limited is an effect I don't find funny.

ciao - chris

--
Christian Tismer :^) <mailto:tis...@tismer.com>
Mission Impossible 5oftware : Have a break! Take a ride on Python's
Johannes-Niemeyer-Weg 9a : *Starship* http://starship.python.net/
14109 Berlin : PGP key -> http://wwwkeys.pgp.net/
work +49 30 89 09 53 34 home +49 30 802 86 56 pager +49 173 24 18 776
PGP 0x57F3BF04 9064 F4E1 D754 C2FF 1619 305B C09C 5A3B 57F3 BF04
whom do you want to sponsor today? http://www.stackless.com/

Chris Gonnerman

unread,
Oct 2, 2002, 11:28:48 PM10/2/02
to

<< apologies... I can't puzzle out some of the >>
<< quoting below, so I've removed the names to >>
<< make it fair. >>

----- Original Message -----
From: "Christian Tismer" <tis...@tismer.com>

> > 1) Should future division return rationals rather than
> > floats.
> >
> > >+1 for returning rationals. It's the right thing -- and
> > >if it fails, it will fail noisily, right?
>
> +1 here, too!
>
> > While I agree with the theoretical arguments, I have
> > the practical fear that rationals could grow very big,
> > rather quickly, in the course of a long computation
> > involving them in various ways. By big, I mean the
> > numerator and denominator of the fraction taken in
> > isolation, not the number itself.

> > Consider inversions of an integer matrices,
> > approximations with truncated series, or worse things
> > like, maybe, discrete Fourier transforms.
>
> Yes, this fear is right.
> I think this is just great. Let it grow! Let the user
> feel what precision he's carrying around, and how much
> they throw away when they reduce down to float.
>
> No I think this is really of advantage. Exact is better
> than small, and it is all in the user's hand. Make a
> float() and you're done.

Practicality beats purity.

If you don't believe me:

>>> import this
The Zen of Python, by Tim Peters

<< hack >>
Although practicality beats purity.
<< hack >>

Yeah, I'm the one who has been arguing in favor of a
decimal arithmetic type in the standard library. Ask
me to support rationals in the standard library, and I'll
back you up. Heck, I'll even accept (optional) rational
literals, like the way we do longs. (As long as you
support (optional) decimal literals in return... :-)

But I don't want to see rationals if I haven't asked for
them. I'm sure nobody wants to see decimals if they
haven't asked for them, either. Principle of least
surprise... if a program I wrote for an earlier version
suddenly starts taking much, much longer to run (maybe
worse: much, much longer *sometimes*), it may cost me a
lot of time to fix it up.

I agree,

1/3

is pretty nice as a rational literal; but would it hurt
so much to say

1/3R

instead?

Chris Gonnerman -- chris.g...@newcenturycomputers.net
http://newcenturycomputers.net


Alex Martelli

unread,
Oct 3, 2002, 2:34:27 AM10/3/02
to
Chris Gonnerman wrote:
...

> I agree,
>
> 1/3
>
> is pretty nice as a rational literal; but would it hurt
> so much to say
>
> 1/3R
>
> instead?

No, it wouldn't hurt much (though I'd spell it with a lowercase r -- I
think that would make it more readable). A trailing d could specify
decimal, a trailing L (normally uppercase for legibility) long -- the
latter should be extended to literals such as:
1e7L
meaning the same as 10000000L -- it's silly to force the author AND
every reader of the source to count out zeroes carefully whenever
such integral literal amounts must be expressed. That's not so crucial
anymore for Italians, now that we've switched from liras to euros,
but, for example, Turkey still uses their own liras, and they're
inflated enough that 1e7L Turkish liras is a few US $...


Alex

John Roth

unread,
Oct 3, 2002, 8:03:19 AM10/3/02
to

<pytho...@ccraig.org> wrote in message
news:mailman.1033596730...@python.org...

> I just uploaded a reference implementation of how rationals might look
> in Python as patch 617779 [1]. I do have some new issues for
> discussion that I'd like to get some comments on before I change the
> PEP.
>
> 1) Should future division return rationals rather than floats. I had
> sort of assumed this would happen, but I just had a discussion with
> Kirby Urner and couldn't convince him it was a good idea, so I guess
> it isn't so clear.

And I don't think you're ever going to get a concensus, for the
simple reason that integer division is an oxymoron. The integers
are not closed under division. The rationals are, and so are the floats
(well, close enough.)

In other words, there is no right answer. Treating an integer
as a degenerate rational makes it look like integer 'division' should
return a rational, but that's simply semantics. You can just as easily
treat an integer as a degenerate float.

The basic issue that there are three separate styles of
arithmetic that give different results on important corner cases.
It's seldom obvious from the program text which is being used,
causing all kinds of confusion.

What I would _perfer_ to do is ban integer division completely,
and replace it by a set of specialty operations that each return
an explicitly defined result type: that is, fdiv, rdiv, idivf, idivr,
idivc.
I doubt that I'll get very much support for this, however.

So I'll vote on leaving it the way it currently is, until Python
3000. That's strictly for compatibility reasons. I see no reason
to force program changes.

John Roth

Alexander Schmolck

unread,
Oct 3, 2002, 9:07:35 AM10/3/02
to
pytho...@ccraig.org writes:
> I just uploaded a reference implementation of how rationals might look
> in Python as patch 617779 [1]. I do have some new issues for
> discussion that I'd like to get some comments on before I change the
> PEP.

Is there any serious reason not to have a rational class that partions into
int[eger]s and rat[io]s (a la common lisp) [*]?

Then ``>>> 1`` would be an int (and also a rational, because int is a subclass
of rational). ``2/2`` would also be the int 1, because rationals that are
expressible as ints are canonicalized to int.``>>> 1 / 2`` on the other hand
would be the rat[io] 1/2.


This solution would seem to me to have the advantage that it is

a) perfectly intuitive to newbies
b) "mathematically correct" and elegant
c) exactness preserving
d) doesn't involve any more or less arbitrary design decisions (e.g. indexing
and similar issues raised in the pep)
e) entails a convenient and natural notation for ratios: ``1/3`` (not 1/3r or
rational(1,3) or whatever)

alex


[*] more precisely, something like this:

rational
/ \
integer ratio
/ \
bignum int

James J. Besemer

unread,
Oct 3, 2002, 9:35:55 AM10/3/02
to

François Pinard wrote:

>On the other hand, [...]


>On average, most programs will not use matrices of rational numbers,
>nor play with series. Moreover, most programs do not use so many different
>numeric variables anyway, nor perform long computations involving them.
>Many programs do not go beyond adding or subtracting one, once in a while!
>

I think this is an excellent point. The prospective active user base
for rationals, at least initially, is a small subset of the user base.

Most people who propose to do much numerical computation often encounter
performance issues and in any case are quickly referred to Numerics
rather than Python intrinsics. Most courses in "Numerical Analysis"
assume floating point arithmetic and include chapters on minimizing loss
of precision.

However more "accurate" Rationals may be in a mathematical sense they
really are a novelty to the majority of computer users and programming
environments. While I support their addition to the language I don't
see that they'd be something I or the majority of users would use on a
routine basis. Like Complex numbers, rationals just don't apply to a
large portion of programming applications.

I certainly think it would be much more confusing for Newbies to find
rational objects showing up and possibly slowing their computation when
they least expect it.

Guido is right that rationals should be off to the side a bit and not
show up in any computations unless expressly introduced by the user.

I think complex numbers are a good model -- naive users can pretty much
ignore their presence altogether and not get into trouble.

>So it might be more
>worth accepting as a community to warn programmers who are more prone to
>numerical algorithms of the intrinsic dangers of integer division in Python.
>

I personally think the "dangers" of integer division have been vastly
exaggerated. Integer division is older than computers and it's really a
trivial concept. The answer cannot be represented accurately so instead
you get an approximation. Furthermore, integer division and integer
modulo together DO produce a complete and exact answer -- a whole number
quotient and a remainder. In my experience, when dealing with integers,
the original integer division result (and the modulo) is more useful in
practice than the "more accurate" floating point result.

That decision is water over the bridge. But substituting a rational for
the present floating point result would only be more confusing.

Regards

--jb

--
James J. Besemer 503-280-0838 voice
2727 NE Skidmore St. 503-280-0375 fax
Portland, Oregon 97211-6557 mailto:j...@cascade-sys.com
http://cascade-sys.com

Charles Krug

unread,
Oct 3, 2002, 10:09:29 AM10/3/02
to
On Thu, 3 Oct 2002 08:03:19 -0400, John Roth <john...@ameritech.net> wrote:
>
><pytho...@ccraig.org> wrote in message
> news:mailman.1033596730...@python.org...
>> I just uploaded a reference implementation of how rationals might look
>> in Python as patch 617779 [1]. I do have some new issues for
>> discussion that I'd like to get some comments on before I change the
>> PEP.
>>
>> 1) Should future division return rationals rather than floats. I had
>> sort of assumed this would happen, but I just had a discussion with
>> Kirby Urner and couldn't convince him it was a good idea, so I guess
>> it isn't so clear.
>
> And I don't think you're ever going to get a concensus, for the
> simple reason that integer division is an oxymoron. The integers
> are not closed under division. The rationals are, and so are the floats
> (well, close enough.)
>
> In other words, there is no right answer. Treating an integer
> as a degenerate rational makes it look like integer 'division' should
> return a rational, but that's simply semantics. You can just as easily
> treat an integer as a degenerate float.
>

Not exactly. Integer division is defined as a theorum, which is called the
Division Algorithm:

Given any two integers a, b with b > 0, there exist unique integers q, r
such that a = bq + r and 0 <= r < b.

It's easy enough to manipulate a and b into the correct form. It's also
fairly easy to prove.

Rationals are defined in terms of integers like this. I wish I were pulling
your leg:

Consider a relation between Z and itself such that for i, j, k, n in Z, with
j != 0 and n != 0:

(i, j) ~ (k, n) if i*n = j*k.

The set of all such ordered pairs is called the Rational Numbers, designated
Q.

Luckily, it's a definition, and doesn't require proof beyond showing that the
squiggle in this case defines an equivalence relation (it does).

From the definition, it's easy to create rationals that are exactly equal to
integer values. The definition of real numbers is even uglier, but it's
sufficiently broad to include both the rationals and the integers.

If you're writing a rational class, I think it's perfectly reasonable in all
cases to return a rational number, as well as to offer conversion operators
into both float and q, r representations.

I don't think it's a matter of semantics as it is a question of modeling
choice and problem decomposition.

Jeff Epler

unread,
Oct 3, 2002, 11:47:43 AM10/3/02
to
On Thu, Oct 03, 2002 at 06:34:27AM +0000, Alex Martelli wrote:
> No, it wouldn't hurt much (though I'd spell it with a lowercase r -- I
> think that would make it more readable). A trailing d could specify
> decimal, a trailing L (normally uppercase for legibility) long -- the
> latter should be extended to literals such as:
> 1e7L
> meaning the same as 10000000L


Would '1.1e7L' also be a long literal under this suggestion?

you could always pollute your namespace with variables of the form 'e%d'
and type '1L*e7' ...

and then there's ways
setlocale(LC_ALL, "en_GB") # surprise the americans
parse_long("ten billion")

Jeff

Erik Max Francis

unread,
Oct 3, 2002, 4:40:00 PM10/3/02
to
John Roth wrote:

> What I would _perfer_ to do is ban integer division completely,
> and replace it by a set of specialty operations that each return
> an explicitly defined result type: that is, fdiv, rdiv, idivf, idivr,
> idivc.
> I doubt that I'll get very much support for this, however.

Because of the upcoming changes for division semantics when the operands
are integers, you're in effect already forced to this; if you want to
write integer division portably, you need to use divmod.

--
Erik Max Francis / m...@alcyone.com / http://www.alcyone.com/max/
__ San Jose, CA, USA / 37 20 N 121 53 W / &tSftDotIotE
/ \ People say that life is the thing, but I prefer reading.
\__/ Logan Pearsall Smith
Computer science / http://www.alcyone.com/max/reference/compsci/
A computer science reference.

Erik Max Francis

unread,
Oct 3, 2002, 4:42:33 PM10/3/02
to
Charles Krug wrote:

> If you're writing a rational class, I think it's perfectly reasonable
> in all
> cases to return a rational number, as well as to offer conversion
> operators
> into both float and q, r representations.

The problem is that the numerator and denominator can silently get huge,
resulting in progressively worse performance. This is especially bad in
the case where this conversion is happening behind the scenes --
suddenly performance starts suffering and no code has changed.

Paul Boddie

unread,
Oct 4, 2002, 3:45:39 AM10/4/02
to
"Chris Gonnerman" <chris.g...@newcenturycomputers.net> wrote in message news:<mailman.1033615625...@python.org>...

>
> But I don't want to see rationals if I haven't asked for
> them.

[...]

> but would it hurt so much to say
>
> 1/3R
>
> instead?

How about the use of specially formed rational literals using the
underscore notation, which I'm sure exists in various other systems?
For example:

1_3

The standard operators would produce rational results from rational
inputs:

1_3 + 2 == 7_3
1_3 - 2 == -5_3
1_3 / 2 == 1_6
1_3 * 2 == 2_3

Use of floating point values in such operations would either produce
errors:

1_3 + 2.5 -> TypeError

Or they could coerce the result to floating point (with the usual
consequences):

1_3 + 2.5 -> 1.0 / 3.0 + 2.5 == 2.8333333333333335

One would then need to define operators or functions to produce
rationals from other types:

rational(1, 3) == 1_3
rational(1) == 1_1
rational(1.5) -> TypeError

And certain built-in functions would need changing:

int(1_3) == 0
float(1_3) -> 1.0 / 3.0 == 0.33333333333333331

I'm sure that all this has been discussed over and over again before,
though.

Paul

Bengt Richter

unread,
Oct 4, 2002, 10:28:38 AM10/4/02
to
On 4 Oct 2002 00:45:39 -0700, pa...@boddie.net (Paul Boddie) wrote:

>"Chris Gonnerman" <chris.g...@newcenturycomputers.net> wrote in message news:<mailman.1033615625...@python.org>...
>>
>> But I don't want to see rationals if I haven't asked for
>> them.
>
>[...]
>
>> but would it hurt so much to say
>>
>> 1/3R
>>
>> instead?
>
>How about the use of specially formed rational literals using the
>underscore notation, which I'm sure exists in various other systems?
>For example:
>
> 1_3
>
>The standard operators would produce rational results from rational
>inputs:
>
> 1_3 + 2 == 7_3
> 1_3 - 2 == -5_3
> 1_3 / 2 == 1_6
> 1_3 * 2 == 2_3
>
>Use of floating point values in such operations would either produce
>errors:
>
> 1_3 + 2.5 -> TypeError

Why? All floating point numbers can be viewed as exact rationals
of the form n_<2**e> with e>=0

>>> R(1,3)
1_3
>>> R(2.5)
5_2
>>> R(1.0, 3.0)
1_3
>>> import math
>>> R(math.pi)
884279719003555_281474976710656

Multiply by big ten power and divide, and you can recognize it

>>> 884279719003555L*10L**40/281474976710656L
31415926535897931159979634685441851615905L
>>> math.pi
3.1415926535897931

the denominator is 2**48
>>> 2l**48
281474976710656L

>
>Or they could coerce the result to floating point (with the usual
>consequences):
>
> 1_3 + 2.5 -> 1.0 / 3.0 + 2.5 == 2.8333333333333335
>
>One would then need to define operators or functions to produce
>rationals from other types:
>
> rational(1, 3) == 1_3
> rational(1) == 1_1
> rational(1.5) -> TypeError

>>> R(1, 3)
1_3
>>> R(1)
1_1
>>> R(1.5)
3_2


>
>And certain built-in functions would need changing:
>
> int(1_3) == 0
> float(1_3) -> 1.0 / 3.0 == 0.33333333333333331
>
>I'm sure that all this has been discussed over and over again before,
>though.
>

Probably ;-)
Using timbot's fixedpoint.py as a template, it should be relatively easy to
hack together something. Getting all the decisions made is another thing ;-)
Regards,
Bengt Richter

Mark Day

unread,
Oct 4, 2002, 8:52:55 PM10/4/02
to
In article <ank8im$33l$0...@216.39.172.122>, Bengt Richter <bo...@oz.net>
wrote:

> >Use of floating point values in such operations would either produce
> >errors:
> >
> > 1_3 + 2.5 -> TypeError
> Why? All floating point numbers can be viewed as exact rationals
> of the form n_<2**e> with e>=0

Automatic conversion to rational pretends those float values are exact,
when they probably weren't meant that way. I would prefer requiring an
explicit conversion rather than an implicit one.

Imagine the uproar when repr(R(1.0/3.0)) looks nothing like
repr(R(1,3)).

-Mark

Alex Martelli

unread,
Oct 5, 2002, 5:10:21 AM10/5/02
to
Mark Day wrote:

> In article <ank8im$33l$0...@216.39.172.122>, Bengt Richter <bo...@oz.net>
> wrote:
>
>> >Use of floating point values in such operations would either produce
>> >errors:
>> >
>> > 1_3 + 2.5 -> TypeError
>> Why? All floating point numbers can be viewed as exact rationals
>> of the form n_<2**e> with e>=0
>
> Automatic conversion to rational pretends those float values are exact,
> when they probably weren't meant that way. I would prefer requiring an
> explicit conversion rather than an implicit one.

In gmpy, at the courteous but adamant insistence of Pearu Peterson,
I introduced a Stern-Brocot algorithm to convert floats to rationals
giving the smallest denominator compatible with the hypothesis that
the float is precise to N bits (N can be any, since gmpy also exposes
via the mpf type the multi-precision floats of the underlying GMP).

The Farey-algorithm, continued-fractions, and other means which have
recently been discussed in python-Dev are presumably more or less
equivalent (I'll of course be quite happy to release the Stern-Brocot
snippet separately from gmpy if anyone needs it with a softer license:
gmpy is LGPL, because I think it may be considered a "derived work"
of GMP, which is itself LGPL).

By default, the number of bits assumed to be accurate for floats
are "all of them" -- usually the DBL_MANT_BITS (or DBL_MANT_DIGS
if FLT_RADIX is 2) from the system's float.h, normally 53 today --
i.e., an imprecision of half an ULP on either side is always
assumed to be possible.

The results seem to be OK for Pearu's symbolic-mathematics purposes,
for casual use, and for every use I've made of the feature myself
(mostly in peculiar combinatorial-arithmetic exercises connected to
card-play probabilities -- but I don't often end up with floats
there except when I'm being lazy and taking shortcuts, admittedly).

[alex@lancelot alex]$ python
Python 2.3a0 (#1, Oct 4 2002, 13:05:05)
[GCC 2.96 20000731 (Mandrake Linux 8.2 2.96-0.76mdk)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from gmpy import mpq, mpf, f2q
>>> mpq('1/3') + 2.5
mpq(17,6)
>>> mpq(1/3.)
mpq(1,3)
>>> mpq('1/3')
mpq(1,3)
>>> mpq(1,3) + 1.0/3.0
mpq(2,3)
>>>

> Imagine the uproar when repr(R(1.0/3.0)) looks nothing like
> repr(R(1,3)).

That might be bad, I guess, but as you see that's not what
happens with gmpy -- Stern-Brocot make it "recover" the value
of 1.0/3.0 as being best approximated by the rational 1/3.

Of course, if I wrongfully claimed to have more bits of
precision than I actually do...:

>>> f2q(1.0/3.0, -53)
mpq(1,3)
>>> f2q(1.0/3.0, -54)
mpq(1,3)
>>> f2q(1.0/3.0, -55)
mpq(6004799503160661L,18014398509481984L)
>>>

...then at some point the rational "explodes" in terms of
size of numerator and denominator. f2q accepts the number
of bits as a second negative argument, or the maximum
tolerable error/approximation when the second argument is
positive, so you don't _have_ to think in binary temrs if
that's not convenient in your application:

>>> f2q(1.0/3.0, 0.0001)
mpq(1,3)
>>>


Alex

Christian Tismer

unread,
Oct 9, 2002, 8:14:12 PM10/9/02
to
Chris Gonnerman wrote:
[snipped all the other good stuff]

> Practicality beats purity.

Absolutely.

> If you don't believe me:
>
> >>> import this
> The Zen of Python, by Tim Peters
>
> << hack >>
> Although practicality beats purity.
> << hack >>
>
> Yeah, I'm the one who has been arguing in favor of a
> decimal arithmetic type in the standard library. Ask
> me to support rationals in the standard library, and I'll
> back you up. Heck, I'll even accept (optional) rational
> literals, like the way we do longs. (As long as you
> support (optional) decimal literals in return... :-)

Ok, we have a deal.

> But I don't want to see rationals if I haven't asked for

> them. I'm sure nobody wants to see decimals if they
> haven't asked for them, either. Principle of least
> surprise... if a program I wrote for an earlier version
> suddenly starts taking much, much longer to run (maybe
> worse: much, much longer *sometimes*), it may cost me a
> lot of time to fix it up.

Naa, this is slightly different.
I don't think al too many people asked for an integer
in the first place when they wrote

1/3

, they just got a zero "since it is so in Python".

Now suddenly for some reason out of this thread's scope
Python reconsiders and thinks it should change this.
So the target of this whole thing is (AFAIK) to figure
out which type to return as the result of integer division?

> I agree,
>
> 1/3
>
> is pretty nice as a rational literal; but would it hurt

> so much to say
>
> 1/3R
>
> instead?

So you would suggest to stick with 1/3 == 0, or return
a float, or a rational?
The latter makes no sense, since this would save the R.

Personally, I don't like the idea to change 1/3 at all
not very much. I see Python doing too much adjustments
at the moment.
Making 1/3 return a float felt like a bad idea, after it
had been int for so many years. Enforcing the float
has become a habit where it's needed.
Now, returning a true fraction instead sounds exciting.
Having fractions in the language is exciting as well,
after I had them in Mathematica for long years.

Finally, if I had to choose, I would either stick with
the old truncation, or use rationals.
Rationals would be welcome, even if there were just
an extension module.

Chris Gonnerman

unread,
Oct 9, 2002, 9:00:13 PM10/9/02
to
----- Original Message -----
From: "Christian Tismer" <tis...@tismer.com>

> Chris Gonnerman wrote:
> [snipped all the other good stuff]

[snipped all the other good stuff again]


> > Yeah, I'm the one who has been arguing in favor of a
> > decimal arithmetic type in the standard library. Ask
> > me to support rationals in the standard library, and I'll
> > back you up. Heck, I'll even accept (optional) rational
> > literals, like the way we do longs. (As long as you
> > support (optional) decimal literals in return... :-)
>
> Ok, we have a deal.

Excellent!

[ hack hack hack ]

> Naa, this is slightly different.
> I don't think al too many people asked for an integer
> in the first place when they wrote
>
> 1/3

Ahhh...

you are thinking, "1/3 as a literal" and I am seeing it as
an EXPRESSION. So to you, this:

1/3

is not the same as this:

n = 1
m = 3

n/m

Or have I misunderstood? Because if you give me a rational
for the second option I'll be royally ticked off. For the
first option, giving me a rational serves me right.



> Now suddenly for some reason out of this thread's scope
> Python reconsiders and thinks it should change this.
> So the target of this whole thing is (AFAIK) to figure
> out which type to return as the result of integer division?

I was against changing the integer division rules (I still
am) but I only have one module affected negatively by it,
so I stopped whining.

(Except when someone brings it up...)



> So you would suggest to stick with 1/3 == 0, or return
> a float, or a rational?

1/3 as an expression; whether I get 0 or 0.333... depends
on the Python version. I just don't want a THIRD option
(gah).

> The latter makes no sense, since this would save the R.

(I don't understand that statement)

> Personally, I don't like the idea to change 1/3 at all
> not very much. I see Python doing too much adjustments
> at the moment.

My reason for not liking automatic insertion of rationals.

> Making 1/3 return a float felt like a bad idea, after it
> had been int for so many years. Enforcing the float
> has become a habit where it's needed.

I agree on both counts.

> Now, returning a true fraction instead sounds exciting.
> Having fractions in the language is exciting as well,
> after I had them in Mathematica for long years.

... let's not get too excited here ...

> Finally, if I had to choose, I would either stick with
> the old truncation, or use rationals.
> Rationals would be welcome, even if there were just
> an extension module.

Now that idea I can get behind. I'd never use them, but
(IMHO) you can never have too many tools in the box.

What I was proposing wasn't actually

1/3R

as a rational literal; THIS is a rational literal:

3R

and since math operations involving a rational and an int
or float would "promote" the int or float to rational, this:

1/3R

would return a rational one-third value.

In other words, the R suffix would make a literal integer
"n" into a rational of the form "n/1".

Christian Tismer

unread,
Oct 9, 2002, 9:44:31 PM10/9/02
to
Chris Gonnerman wrote:

[snipped good stuff again, including stuff snipped]

>>Naa, this is slightly different.
>>I don't think al too many people asked for an integer
>>in the first place when they wrote
>>
>> 1/3
>
>
> Ahhh...
>
> you are thinking, "1/3 as a literal" and I am seeing it as
> an EXPRESSION. So to you, this:
>
> 1/3
>
> is not the same as this:
>
> n = 1
> m = 3
>
> n/m
>
> Or have I misunderstood? Because if you give me a rational
> for the second option I'll be royally ticked off. For the
> first option, giving me a rational serves me right.

No, sorry, I didn't distinguish literal form expression.
The 1/3r thingie appeared on python-dev, and I perceived
it as a modifier for the whole expression.
Probably wrong, and you are right with 3r = rational(3,1)
There had been proposals like 1:3, [1:3] and so on,
and I was thinking of syntactic sugar for the whole
expression.
...bigger snip...

>>Now, returning a true fraction instead sounds exciting.
>>Having fractions in the language is exciting as well,
>>after I had them in Mathematica for long years.
>
>
> ... let's not get too excited here ...
>
>
>>Finally, if I had to choose, I would either stick with
>>the old truncation, or use rationals.
>>Rationals would be welcome, even if there were just
>>an extension module.
>
>
> Now that idea I can get behind. I'd never use them, but
> (IMHO) you can never have too many tools in the box.
>
> What I was proposing wasn't actually
>
> 1/3R
>
> as a rational literal; THIS is a rational literal:
>
> 3R

Now it is clear.

> and since math operations involving a rational and an int
> or float would "promote" the int or float to rational, this:
>
> 1/3R
>
> would return a rational one-third value.
>
> In other words, the R suffix would make a literal integer
> "n" into a rational of the form "n/1".

That's good anyway, and not related to a decision what 1/3
should be. Let's see what comes...

ciao - chris[2]

Bengt Richter

unread,
Oct 9, 2002, 11:26:02 PM10/9/02
to
On Thu, 03 Oct 2002 06:35:55 -0700, "James J. Besemer" <j...@cascade-sys.com> wrote:

>
>Fran=E7ois Pinard wrote:
>
>>On the other hand, [...]
>>On average, most programs will not use matrices of rational numbers,

>>nor play with series. Moreover, most programs do not use so many differ=


>ent
>>numeric variables anyway, nor perform long computations involving them.

>>Many programs do not go beyond adding or subtracting one, once in a whil=
>e!
>>
>I think this is an excellent point. The prospective active user base=20
>for rationals, at least initially, is a small subset of the user base. =20
>
>Most people who propose to do much numerical computation often encounter=20
>performance issues and in any case are quickly referred to Numerics=20
>rather than Python intrinsics. Most courses in "Numerical Analysis"=20
>assume floating point arithmetic and include chapters on minimizing loss=20
>of precision.
>
>However more "accurate" Rationals may be in a mathematical sense they=20
>really are a novelty to the majority of computer users and programming=20
>environments. While I support their addition to the language I don't=20
>see that they'd be something I or the majority of users would use on a=20
>routine basis. Like Complex numbers, rationals just don't apply to a=20


>large portion of programming applications.
>

>I certainly think it would be much more confusing for Newbies to find=20
>rational objects showing up and possibly slowing their computation when=20
>they least expect it.
>
>Guido is right that rationals should be off to the side a bit and not=20
>show up in any computations unless expressly introduced by the user. =20
>
Why not a way to introduce special rules for a limited scope? E.g., if there
were a 'scope' keyword that would introduce in indented block where the rules
would apply, and a dictionary defining rules and hooks. Then you could write

scope rational_rules:
a = b/c # the '/' operator coerces to rational, let's say
blah() # blah's internal rules would not be affected
d = a # would have to act according to enclosing scope

rational_rules might be {'enter_scope':__enter_rational__,
'leave_scope':__leave_rational__,
'exception_hook': __rational_exception__, ...}

More than one set of rules is conceivable, as a sequence of dictionaries.
This would allow calling some C magic for messing with internal state as needed for
efficient implementation of standardly available scope rules, or doing
stuff in Python. This is just OTTOMH this moment, but I thought it might be interesting
to post before I forget it ;-)

You could import stuff (e.g., from __future__) or whatever. The scope keyword would
generate compiler code to call the hooks from the mandatory rules dictionary
(or expression evaluating to a dictionary) following. I threw in something for escaping
exception handling, in case some processing was needed/desired

>I think complex numbers are a good model -- naive users can pretty much=20


>ignore their presence altogether and not get into trouble.
>
>>So it might be more
>>worth accepting as a community to warn programmers who are more prone to

>>numerical algorithms of the intrinsic dangers of integer division in Pyt=
>hon.
>>
>
>I personally think the "dangers" of integer division have been vastly=20
>exaggerated. Integer division is older than computers and it's really a=20
>trivial concept. The answer cannot be represented accurately so instead=20
>you get an approximation. Furthermore, integer division and integer=20
>modulo together DO produce a complete and exact answer -- a whole number=20
>quotient and a remainder. In my experience, when dealing with integers,=20
>the original integer division result (and the modulo) is more useful in=20
>practice than the "more accurate" floating point result. =20
>
You'd probably like

scope classic_division:
assert 3/4==0
...

for some stuff ?

>That decision is water over the bridge. But substituting a rational for=20


>the present floating point result would only be more confusing.

Unless, perhaps, it could be limited explicitly to a particular scope.
I'm sure there's a lot of sneaky issues involving state created within
a special scope being referenced from a different (maybe differently special
or ordinary) scope, but that's further along the discussion. The first part
is would it be a natural-feeling way to express coding intent. The rest would
be a SMIP ("simple" matter of implementation ;-)

Regards,
Bengt Richter

James J. Besemer

unread,
Oct 10, 2002, 12:26:10 AM10/10/02
to

Bengt Richter wrote:

>Why not a way to introduce special rules for a limited scope? E.g., if there
>were a 'scope' keyword that would introduce in indented block where the rules
>would apply, and a dictionary defining rules and hooks. Then you could write
>
> scope rational_rules:
> a = b/c # the '/' operator coerces to rational, let's say
> blah() # blah's internal rules would not be affected
> d = a # would have to act according to enclosing scope
>
>rational_rules might be {'enter_scope':__enter_rational__,
> 'leave_scope':__leave_rational__,
> 'exception_hook': __rational_exception__, ...}
>
>More than one set of rules is conceivable, as a sequence of dictionaries.
>
>

This is an interesting idea but it strikes me as overly "inventive." It
would be a much bigger change to Python than simply adding rationals.

>You could import stuff (e.g., from __future__) or whatever.
>

If anything as dramatic as changing division to produce rational results
is introduced I think it should apply globally to the entire module, not
selectively per scope.

And I don't see any need for "special scope rules".

In any context where rational numbers already exist, we can define "/"
to work naturally. That is any division involving one or more rational
arguments would product a rational result.

Personally, I don't have a problem saying something like "rat( 3, 4 )"
to introduce a new rational. It's consistent with the rest of Python's
OO.

Alternatively, a "R" suffix to ordinary integers would be pretty clean,
e.g., you could say "3/4R".

Personally, FWIW, I oppose changing builtins so that int(x)/int(y)
produces a rational. For the small minority who would use rationals,
one of the above forms should be no hardship.

>You'd probably like
>
> scope classic_division:
> assert 3/4==0
> ...
>
>for some stuff ?
>

I count myself among the people who did not want integer division to
change from it's original definition.

However, given that it HAS changed, I don't think it should vary on a
per-scope basis. At least not beyond:

assert int( 3/4 ) == 0
or
assert 3//4 == 0

0 new messages