471,309 Members | 1,551 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,309 software developers and data experts.

A rational proposal

PEP: XXX
Title: A rational number module for Python
Version: $Revision: 1.4 $
Last-Modified: $Date: 2003/09/22 04:51:50 $
Author: Mike Meyer <mw*@mired.org>
Status: Draft
Type: Staqndards
Content-Type: text/x-rst
Created: 16-Dec-2004
Python-Version: 2.5
Post-History: 30-Aug-2002
Abstract
========

This PEP proposes a rational number module to add to the Python
standard library.
Rationale
=========

Rationals are a standard mathematical concept, included in a variety
of programming languages already. Python, which comes with 'batteries
included' should not be deficient in this area. When the subject was
brought up on comp.lang.python several people mentioned having
implemented a rational number module, one person more than once. In
fact, there is a rational number module distributed with Python as an
example module. Such repetition shows the need for such a class in the
standard library.

There are currently two PEPs dealing with rational numbers - 'Adding a
Rational Type to Python' [#PEP-239] and 'Adding a Rational Literal to
Python' [#PEP-240], both by Craig and Zadka. This PEP competes with
those PEPs, but does not change the Python language as those two PEPs
do [#PEP-239-implicit]. As such, it should be easier for it to gain
acceptance. At some future time, PEP's 239 and 240 may replace the
``rational`` module.
Specification
=============

The module shall be ``rational``, and the class ``Rational``, to
follow the example of the decimal [#PEP-327] module. The class
creation method shall accept as arguments a numerator, and an optional
denominator, which defaults to one. Both the numerator and
denominator - if present - must be of integer type. Since all other
numeric types in Python are immutable, Rational objects will be
immutable. Internally, the representation will insure that the
numerator and denominator have a greatest common divisor of 1, and
that the sign of the denominator is positive.

The ``Rational`` class shall define all the standard mathematical
operations: addition, subtraction, multiplication, division, modulo
and power. It will also provide the methods:

- max(*args): return the largest of a list of numbers and self.
- min(*args): return the smallest of a list of numbers and self.
- decimal(): return the decimal approximation to the rational in the
current context.
- inv(): Return the inverse of self.

Rationals will mix with all other numeric types. When combined with an
integer type, that integer will be converted to a rational before the
operation. When combined with a floating type - either complex or
float - the rational will be converted to a floating approximation
before the operation, and a float or complex will be returned. The
reason for this is that floating point numbers - including complex -
are already imprecise. To convert them to rational would give an
incorrect impression that the results of the operation are
precise. Decimals will be converted to rationals before the
operation. [Open question: is this the right thing to do?]

Rationals can be converted to floats by float(rational), and to
integers by int(rational).

The module will define and at times raise the following exceptions:

- DivisionByZero: divide by zero
- OverflowError: overflow attempting to convert to a float.

Implementation
==============

There is currently a rational module distributed with Python, and a
second rational module in the Python cvs source tree that is not
distributed. While one of these could be chosen and made to conform
to the specification, I am hoping that several people will volunteer
implementatins so that a ''best of breed'' implementation may be
chosen.
References
==========

... [#PEP-239] Adding a Rational Type to Python, Craig, Zadka
(http://www.python.org/peps/pep-0239.html)
... [#PEP-240] Adding a Rational Literal to Python, Craig, Zadka
(http://www.python.org/peps/pep-0240.html)
... [#PEP-327] Decimal Data Type, Batista
(http://www.python.org/peps/pep-0327.html)
... [#PEP-239-implicit] PEP 240 adds a new literal type to Pytbon,
PEP 239 implies that division of integers would
change to return rationals.
Copyright
=========

This document has been placed in the public domain.

...
Local Variables:
mode: indented-text
indent-tabs-mode: nil
sentence-end-double-space: t
fill-column: 70
End:
Jul 18 '05 #1
21 2206
Mike Meyer wrote:
PEP: XXX
Title: A rational number module for Python

<snip>

I think it is a good idea to have rationals as part of the standard
distribution but why not base this on the gmpy module
(https://sourceforge.net/projects/gmpy)? That module already provides
good performance. However, it does a few things that may not be good ideas.

1. Floats are converted to rationals. I think your proposal of rational
to float is better.

2. Fails with a TypeError when used with a complex. Again Your proposal
provides a better solution.

3. Fractional powers fail with a ValueError if the root is not exact.
You do not address this in your proposal. Could silently convert to
float in this case but is it better to force the user to be explicit and
use the float() operation?

Ray Buvel
Jul 18 '05 #2

"Mike Meyer" <mw*@mired.org> wrote in message
news:86************@guru.mired.org...
PEP: XXX
Title: A rational number module for Python
Version: $Revision: 1.4 $
Last-Modified: $Date: 2003/09/22 04:51:50 $
Author: Mike Meyer <mw*@mired.org>
Status: Draft
Type: Staqndards
Content-Type: text/x-rst
Created: 16-Dec-2004
Python-Version: 2.5
Post-History: 30-Aug-2002
Abstract
========

This PEP proposes a rational number module to add to the Python
standard library.
[snip]
The ``Rational`` class shall define all the standard mathematical
operations: addition, subtraction, multiplication, division, modulo
and power. It will also provide the methods:

- max(*args): return the largest of a list of numbers and self.
- min(*args): return the smallest of a list of numbers and self.
max() and min() are already part of the standard library.
Providing them as instance methods is quite irregular.
- decimal(): return the decimal approximation to the rational in the
current context.
This ought to be the responsibility of the decimal() constructor.
I can see including it here to avoid adding it to the decimal()
constructor, but IMO it's bad design.
- inv(): Return the inverse of self.
I presume this means that if the rational is x/y, then it
returns y/x?
Rationals will mix with all other numeric types. When combined with an
integer type, that integer will be converted to a rational before the
operation. When combined with a floating type - either complex or
float - the rational will be converted to a floating approximation
before the operation, and a float or complex will be returned. The
reason for this is that floating point numbers - including complex -
are already imprecise. To convert them to rational would give an
incorrect impression that the results of the operation are
precise. Decimals will be converted to rationals before the
operation. [Open question: is this the right thing to do?]
I'd prefer to have rationals converted to decimals before
the operation, for the same reason that they're converted
to floats. Decimals also have limited precision.
Rationals can be converted to floats by float(rational), and to
integers by int(rational).


If this is the case, then there is no reason to have a separate
member operation to convert rationals to decimal. Consistency
says to do it the same way for all similar operations.

....

John Roth

Jul 18 '05 #3
"Raymond L. Buvel" <le******@wi.rr.com> writes:
Mike Meyer wrote:
PEP: XXX
Title: A rational number module for Python <snip>

I think it is a good idea to have rationals as part of the standard
distribution but why not base this on the gmpy module
(https://sourceforge.net/projects/gmpy)? That module already provides
good performance. However, it does a few things that may not be good
ideas.


It wraps a third party package, which can't really be added to the
standard libraray. The documentation for a rationa number package in
Python should include a pointer to gmpy with a note about performance.
3. Fractional powers fail with a ValueError if the root is not
exact. You do not address this in your proposal. Could silently
convert to float in this case but is it better to force the user to be
explicit and use the float() operation?


You're right. Raising a rational to a rational power isn't covered,
and may produce an irrational answer. Raising a rational to a floating
point power will cause the rational to be converted to a float, as is
specified.

I think forcing the use of float is wrong, as the rational may be an
integer. I'm not sure what should be done, so this is being added as
an open issue.

Thanks,
<mike
--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Jul 18 '05 #4
"John Roth" <ne********@jhrothjr.com> writes:
"Mike Meyer" <mw*@mired.org> wrote in message
news:86************@guru.mired.org...
PEP: XXX
Title: A rational number module for Python
The ``Rational`` class shall define all the standard mathematical
operations: addition, subtraction, multiplication, division, modulo
and power. It will also provide the methods:

- max(*args): return the largest of a list of numbers and self.
- min(*args): return the smallest of a list of numbers and self.


max() and min() are already part of the standard library.
Providing them as instance methods is quite irregular.


They don't handle decimals or rationals. This is following the lead of
the decimal package.
- decimal(): return the decimal approximation to the rational in the
current context.


This ought to be the responsibility of the decimal() constructor.
I can see including it here to avoid adding it to the decimal()
constructor, but IMO it's bad design.


Good point. Currently, objects now how to convert themselves to int,
float and complex. Should Rational now how to convert itself to
Decimal (and conversely, decimal now how to convert itself to
Rational)?
- inv(): Return the inverse of self.

I presume this means that if the rational is x/y, then it
returns y/x?


Is this better wording:
- inv(): Return self to the power -1.

Rationals will mix with all other numeric types. When combined with an
integer type, that integer will be converted to a rational before the
operation. When combined with a floating type - either complex or
float - the rational will be converted to a floating approximation
before the operation, and a float or complex will be returned. The
reason for this is that floating point numbers - including complex -
are already imprecise. To convert them to rational would give an
incorrect impression that the results of the operation are
precise. Decimals will be converted to rationals before the
operation. [Open question: is this the right thing to do?]


I'd prefer to have rationals converted to decimals before
the operation, for the same reason that they're converted
to floats. Decimals also have limited precision.


I'm of two minds about this one. One is that decimals have limited
precision. But they represent their values exactly, whereas 1E73 isn't
a 1 followed by 73 zeros when converted to an int. On the other hand,
every decimal has a rational equivalent, but not vice versa.

Thanks,
<mike
--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Jul 18 '05 #5
[Jp Calderone]
....
The Decimal type seems to define min and max so that NaNs
can be treated specially, but I glean this understanding from only
a moment of reading decimal.py. Perhaps someone more well
informed can declare definitively the purpose of these methods.


To conform to the semantics of the min and max operations defined in
IBM's proposed standard for decimal arithmetic:

http://www2.hursley.ibm.com/decimal/

and in particular:

http://www2.hursley.ibm.com/decimal/daops.html#refmax
and
http://www2.hursley.ibm.com/decimal/daops.html#refmin

Note that this is a moving target.
Jul 18 '05 #6

"Mike Meyer" <mw*@mired.org> wrote in message
news:86************@guru.mired.org...
Title: A rational number module for Python

<snip>


1. I would call this Not Necessary but Nice. Perhaps the time has come to
include rationals in the Standard Library, given that its expansion will be
a focus of the 2.5 cycle. It certainly seems time to have such a PEP
pushed to a formal decision.

To increase the chance of getting BDFL approval, you might search clp and
especially pydev archives for Guido's (and maybe other developers') past
objections and prepare to meet them. I vaguely remember things like too
specialized and not needed enough, need already met by third party modules,
and the inherent clumbsiness of exact rational calculations (due to length
growth of 'ators and the time needed to remove common factors, if one
does).

2. The initial and debugged implementation should be in Python at least
until the interface and behavioral specs are finalized. Beside the obvious
reasons, this will help the PyPy project which is currently being slowed a
bit by the needed to rewrite C-coded modules in Python.

Terry J. Reedy

Jul 18 '05 #7
Mike Meyer wrote:
max() and min() are already part of the standard library.
Providing them as instance methods is quite irregular.
They don't handle decimals or rationals. This is following the lead of
the decimal package.


As Tim pointed out - decimal has its own versions of max & min which conform to
the decimal specification.

For the builtin in max and min, decimal's behave like any other number.
- decimal(): return the decimal approximation to the rational in the
current context.


This ought to be the responsibility of the decimal() constructor.
I can see including it here to avoid adding it to the decimal()
constructor, but IMO it's bad design.


Actually, what's missing at the moment is the decimal equivalent of __int__,
__float__, etc.

Generally, for new types, it is the new type's responsibility to play well with
pre-existing types, not the other way round (think about what the __str__ method
actually does - it's the type conversion method for turning your object into a
string object)
Good point. Currently, objects now how to convert themselves to int,
float and complex. Should Rational now how to convert itself to
Decimal (and conversely, decimal now how to convert itself to
Rational)?


Doing either of those properly requires adding slots to the type structure
(since you need new magic methods - __decimal__ and __rational__).

I believe the goal is to have Decimal.decimal become a builtin for Py 2.5, in
which case, I would also hope to see a __decimal__ special method.

The correct answer would then be for Rational.rational to handle decimals in its
constructor, and provide an implementation of __decimal__ (similar to the way
Decimal.decimal interacts with the other builtin types).

Cheers,
Nick.

--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #8
Raymond L. Buvel <le******@wi.rr.com> wrote:
Mike Meyer wrote:
PEP: XXX
Title: A rational number module for Python

<snip>

I think it is a good idea to have rationals as part of the standard
distribution but why not base this on the gmpy module
(https://sourceforge.net/projects/gmpy)? That module already provides


gmpy wraps GMP, which is covered by LGPL; therefore, gmpy itself is
LGPL, and thus, sadly, cannot be included with python (otherwise,
speaking as gmpy's author, I'd be glad to fix its design to meet your
objections).
Alex
Jul 18 '05 #9
al*****@yahoo.com (Alex Martelli) writes:
gmpy wraps GMP, which is covered by LGPL; therefore, gmpy itself is
LGPL, and thus, sadly, cannot be included with python (otherwise,
speaking as gmpy's author, I'd be glad to fix its design to meet your
objections).


There's no obstacle to including LGPL'd modules as part of the Python
distribution as long as those modules are also offered as source code.
The LGPL does place some conditions on how LGPL'd modules can be
further redistributed, which users would have to abide by; that might
or might not be considered undesirable for Python distro purposes.
There's certainly no reason the Python docs can't point to modules
like gmpy. They already point to code and documentation that's
flat-out proprietary.
Jul 18 '05 #10
Alex Martelli wrote:
Raymond L. Buvel <le******@wi.rr.com> wrote:

Mike Meyer wrote:
PEP: XXX
Title: A rational number module for Python


<snip>

I think it is a good idea to have rationals as part of the standard
distribution but why not base this on the gmpy module
(https://sourceforge.net/projects/gmpy)? That module already provides

gmpy wraps GMP, which is covered by LGPL; therefore, gmpy itself is
LGPL, and thus, sadly, cannot be included with python (otherwise,
speaking as gmpy's author, I'd be glad to fix its design to meet your
objections).
Alex


Since the LGPL was designed to allow propritary software to link to a
LGPL module, I don't see why any software under a free license like
Python cannot link to the GMP library. The PSF may want you to release
gmpy under a dual license if it is incorporated into the Python standard
library but I don't see why that cannot be done.

Ray
Jul 18 '05 #11
Raymond L. Buvel wrote:
gmpy wraps GMP, which is covered by LGPL; therefore, gmpy itself is
LGPL, and thus, sadly, cannot be included with python (otherwise,
speaking as gmpy's author, I'd be glad to fix its design to meet your
objections).
Since the LGPL was designed to allow propritary software to link to a LGPL module, I don't see why
any software under a free license like Python cannot link to the GMP library. The PSF may want
you to release gmpy under a dual license if it is incorporated into the Python standard library
but I don't see why that cannot be done.


core features cannot rely on software components with restrictive licenses.

nothing stops a Python distributor from shipping Python builds with LGPL'ed
(or GPL'ed) components today; Alex was talking about the core distribution.

</F>

Jul 18 '05 #12
Hi Mike - Thanks for taking the time to put this together.

In article <86************@guru.mired.org>, Mike Meyer wrote:
- max(*args): return the largest of a list of numbers and self.
- min(*args): return the smallest of a list of numbers and self.
I would strongly prefer either adapting the already built-in min/max
functions to support this type or creating functions in a module rather than
using the method approach. My reason is the assymetry; I would much prefer:

rational.max(rat1, rat2, rat3)

over:

rat1.max(rat2, rat3)

for the simple reason that the latter looks unbalanced and empbasizes "rat1"
when there is really no reason to do so.
Rationals will mix with all other numeric types. When combined with an
integer type, that integer will be converted to a rational before the
operation. When combined with a floating type - either complex or
float - the rational will be converted to a floating approximation
before the operation, and a float or complex will be returned. The
reason for this is that floating point numbers - including complex -
are already imprecise. To convert them to rational would give an
incorrect impression that the results of the operation are
precise. Decimals will be converted to rationals before the
operation. [Open question: is this the right thing to do?]


Sounds right to me.

Cheers,
Dave

--
.:[ dave benjamin: ramen/[sp00] -:- spoomusic.com -:- ramenfest.com ]:.
"talking about music is like dancing about architecture."
Jul 18 '05 #13
I've been thinking about doing this for a while. cRat
(http://sf.net/projects/pythonic) already meets these qualifications
except that I need to add decimal support to it now that decimals are
in the language. I could rewrite the existing code in Python (it's
currently in C), but there are some very real performance reasons to
do it in C rather than Python (i.e. I'm manipulating the internals of
the numerator and denominator by hand for performance in the GCD
function)

--
Christopher A. Craig <co********@ccraig.org>
"I affirm brethren by the boasting in you which I have in Christ Jesus
our Lord, I die daily" I Cor 15:31 (NASB)

Jul 18 '05 #14
On Fri, 17 Dec 2004 21:29:52 -0600, Mike Meyer <mw*@mired.org> wrote:
PEP: XXX
Title: A rational number module for Python
Version: $Revision: 1.4 $
Last-Modified: $Date: 2003/09/22 04:51:50 $
Author: Mike Meyer <mw*@mired.org>
Status: Draft
Type: Staqndards
Content-Type: text/x-rst
Created: 16-Dec-2004
Python-Version: 2.5
Post-History: 30-Aug-2002
Abstract
========

This PEP proposes a rational number module to add to the Python
standard library.
Rationale
=========

Rationals are a standard mathematical concept, included in a variety
of programming languages already. Python, which comes with 'batteries
included' should not be deficient in this area. When the subject was
brought up on comp.lang.python several people mentioned having
implemented a rational number module, one person more than once. In
fact, there is a rational number module distributed with Python as an
example module. Such repetition shows the need for such a class in the
standard library.

There are currently two PEPs dealing with rational numbers - 'Adding a
Rational Type to Python' [#PEP-239] and 'Adding a Rational Literal to
Python' [#PEP-240], both by Craig and Zadka. This PEP competes with
those PEPs, but does not change the Python language as those two PEPs
do [#PEP-239-implicit]. As such, it should be easier for it to gain
acceptance. At some future time, PEP's 239 and 240 may replace the
``rational`` module.
Specification
=============

The module shall be ``rational``, and the class ``Rational``, to
follow the example of the decimal [#PEP-327] module. The class
creation method shall accept as arguments a numerator, and an optional
denominator, which defaults to one. Both the numerator and
denominator - if present - must be of integer type. Since all other
numeric types in Python are immutable, Rational objects will be
immutable. Internally, the representation will insure that the
numerator and denominator have a greatest common divisor of 1, and
that the sign of the denominator is positive. IMO a string should also be a legitimate constructor argument,
as e.g. it is for int. This also provides the opportunity to accept
strings ordinarily representing floating point values and convert them
to exact rationals. E.g., '1.23' is exactly 123/100 so IWT it convenient
if rational.rat('1.23') == rational.rat(123, 100).

This principle is easily extended to '1.23e-45' etc., since any similar
otherwise-floating-point literal string can be represented exactly as
a rational if integer values of numerator and denominator are not limited
-- which they aren't in Python. Decimal floating point literal notation is
quite handy, and it is easy and exact to convert to rational, though
the reverse in not possible in general. A small further extension to literal
representation is to allow two of the aforementioned style of literals
to be joined with a '/' so that rat('x/y') == rat('x')/rat('y')
-- i.e., you could implement this extension of literal format by just trying
a literal_string.split('/') and doing the obvious. This also creates
a possible general repr format that can represent any rational accurately,
and the possibility if desired of a "friendly" __str__ format where a denominator
can be made a power of 10, e.g. '0.6' where __repr__ would be '3/5'.

The ``Rational`` class shall define all the standard mathematical
operations: addition, subtraction, multiplication, division, modulo
and power. It will also provide the methods:

- max(*args): return the largest of a list of numbers and self.
- min(*args): return the smallest of a list of numbers and self.
- decimal(): return the decimal approximation to the rational in the
current context.
- inv(): Return the inverse of self.

Rationals will mix with all other numeric types. When combined with an
integer type, that integer will be converted to a rational before the
operation. When combined with a floating type - either complex or
float - the rational will be converted to a floating approximation
before the operation, and a float or complex will be returned. The
reason for this is that floating point numbers - including complex -
are already imprecise. To convert them to rational would give an
incorrect impression that the results of the operation are
precise. Decimals will be converted to rationals before the
operation. [Open question: is this the right thing to do?] Sounds right, iff the decimal really does represent an exact value.
But after a division or multiplication of decimals, I'm not sure I'm
comfortable with calling those results exact in the same sense as
if the operations had been with rationals.

IMO the issue of exactness deserves particular emphasis. Otherwise
why even bother with a rational type? If a decimal represents an exact
value, then it should become an exact rational in operations with rationals.

If you define the result of some rounding operations as exact, then
you could make exact rationals from the results. E.g., the string literal
argument would let you take an inexact float
f = 0.1
and round int with string formatting and convert thus
r = rat('%.2f'%f) # could also pass a rounding spec to rat, like rat(f, 2)

and similarly with a decimal type. So that's one mechanism to do capture
of exact values from values known to represent a set of exact values using a set
of approximations that cluster around the exact values in way that makes
unambiguous determination of the represented values possible. (I'm trying to
state it like a patent lawyer grabbing for unanticipated general coverage ;-)
Rationals can be converted to floats by float(rational), and to
integers by int(rational).

The module will define and at times raise the following exceptions:

- DivisionByZero: divide by zero
- OverflowError: overflow attempting to convert to a float. I wonder if forced conversion to float or complex from some operation shouldn't
be an exception too. The result could be passed in the exception object, so it
would be easy to wrap risky operations in try/except. Or is a test for
isinstance(x, (float, complex)) the way to go? Is inexactness an exception w.r.t rational?
Implementation
==============

There is currently a rational module distributed with Python, and a
second rational module in the Python cvs source tree that is not
distributed. While one of these could be chosen and made to conform
to the specification, I am hoping that several people will volunteer
implementatins so that a ''best of breed'' implementation may be
chosen.
References
==========

.. [#PEP-239] Adding a Rational Type to Python, Craig, Zadka
(http://www.python.org/peps/pep-0239.html)
.. [#PEP-240] Adding a Rational Literal to Python, Craig, Zadka
(http://www.python.org/peps/pep-0240.html)
.. [#PEP-327] Decimal Data Type, Batista
(http://www.python.org/peps/pep-0327.html)
.. [#PEP-239-implicit] PEP 240 adds a new literal type to Pytbon,
PEP 239 implies that division of integers would
change to return rationals.
Copyright
=========

This document has been placed in the public domain.

..
Local Variables:
mode: indented-text
indent-tabs-mode: nil
sentence-end-double-space: t
fill-column: 70
End:


Regards,
Bengt Richter
Jul 18 '05 #15
Mike Meyer wrote:
"John Roth" <ne********@jhrothjr.com> writes:
"Mike Meyer" <mw*@mired.org> wrote in message
news:86************@guru.mired.org...
PEP: XXX
Title: A rational number module for Python .... Rationals will mix with all other numeric types. When combined with an integer type, that integer will be converted to a rational before the operation. When combined with a floating type - either complex or
float - the rational will be converted to a floating approximation
before the operation, and a float or complex will be returned. The reason for this is that floating point numbers - including complex - are already imprecise. To convert them to rational would give an
incorrect impression that the results of the operation are
precise. Decimals will be converted to rationals before the
operation. [Open question: is this the right thing to do?]
I'd prefer to have rationals converted to decimals before
the operation, for the same reason that they're converted
to floats. Decimals also have limited precision.


I'm of two minds about this one. One is that decimals have limited
precision. But they represent their values exactly,


You just contradicted yourself.

The decimal class exactly represents numbers that have exact, concise
representations in decimal, such as monetary amounts. It doesn't
represent arbitary numbers exactly. Otherwise, why bother implememting
a rational class?

.... On the other hand,
every decimal has a rational equivalent, but not vice versa.

The same statement is true for floats.

Jul 18 '05 #16
co********@ccraig.org (Christopher A. Craig) writes:
I've been thinking about doing this for a while. cRat
(http://sf.net/projects/pythonic) already meets these qualifications
except that I need to add decimal support to it now that decimals are
in the language. I could rewrite the existing code in Python (it's
currently in C), but there are some very real performance reasons to
do it in C rather than Python (i.e. I'm manipulating the internals of
the numerator and denominator by hand for performance in the GCD
function)


I hadn't considered doing a C implementation until we had experience
with a Python implementation to learn from. But if you've got this and
are willing to release it under a license that allows inclusion in
Python, that would be great. I'm willing to do the work to get
decimals working properly with it.

<mike
--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Jul 18 '05 #17
Mike Meyer wrote:
I'm willing to do the work to get
decimals working properly with it.


Facundo's post reminded me of some of the discussion about the interaction
between floats and Decimal that went on when he was developing the module that
eventually made it into the standard library.

Perhaps Rational should have the same "arm's length" interaction with floats
that Decimal does - require the user to set the precision they want by turning
the float into a string that is then fed to the Rational constructor. My
argument is that the following behaviour might be a little disconcerting:

Py> x = 1.1
Py> Rational(x)
Rational("11000000000000001 / 10000000000000000")

as opposed to:
Py> x = 1.1
Py> Rational("%.2f" % x)
Rational("11 / 10")

(A direct Decimal->Rational conversion should be OK, however, since it should
match standard expections regarding the behaviour of the fractional portion)

The other point is that, since converting a Rational to float() or Decimal() may
lose information, this is something that Python shouldn't really do
automatically. As Facundo suggested, a string representation is a suitable
intermediate format that makes explicit the degree of precision used in the
conversion.

Cheers,
Nick.

--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #18
Nick Coghlan <nc******@iinet.net.au> writes:
Mike Meyer wrote:
I'm willing to do the work to get
decimals working properly with it.
Facundo's post reminded me of some of the discussion about the
interaction between floats and Decimal that went on when he was
developing the module that eventually made it into the standard
library.

Perhaps Rational should have the same "arm's length" interaction with
floats that Decimal does - require the user to set the precision they
want by turning the float into a string that is then fed to the
Rational constructor. My argument is that the following behaviour
might be a little disconcerting:

Py> x = 1.1
Py> Rational(x)
Rational("11000000000000001 / 10000000000000000")


Yeah. That's why the spec specified integers for the argumetns.
as opposed to:
Py> x = 1.1
Py> Rational("%.2f" % x)
Rational("11 / 10")

(A direct Decimal->Rational conversion should be OK, however, since it
should match standard expections regarding the behaviour of the
fractional portion)
Yeah. I've already added that to my copy of the PEP. That makes
rationals like (1/"1E1000") much easier to represent properly.
The other point is that, since converting a Rational to float() or
Decimal() may lose information, this is something that Python
shouldn't really do automatically. As Facundo suggested, a string
representation is a suitable intermediate format that makes explicit
the degree of precision used in the conversion.


Well, you want to be able to add floats to rationals. The results
shouldn't be rational, for much the same reason as you don't want to
convert floats to rationals directly. I figure the only choice that
leaves is that the result be a float. That and float(rational) should
be the only times that a rational gets turned into a float.

Are you suggestiong that float(rational) should be a string, with the
number of degrees of precesion set by something like the Context type
in Decimal?

<mike
--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Jul 18 '05 #19
Mike Meyer wrote:
Well, you want to be able to add floats to rationals. The results
shouldn't be rational, for much the same reason as you don't want to
convert floats to rationals directly. I figure the only choice that
leaves is that the result be a float. That and float(rational) should
be the only times that a rational gets turned into a float.

Are you suggestiong that float(rational) should be a string, with the
number of degrees of precesion set by something like the Context type
in Decimal?


Actually, I was misremembering how Decimal worked - it follows the rule you suggest:

float() + Decimal() fails with a TypeError
float() + float(Decimal()) works fine

And I believe Decimal's __float__ operation is a 'best effort' kind of thing, so
I have no problem with Rationals working the same way.

Cheers,
Nick.

--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #20
Nick Coghlan <nc******@iinet.net.au> writes:
Actually, I was misremembering how Decimal worked - it follows the rule you suggest:

float() + Decimal() fails with a TypeError
float() + float(Decimal()) works fine

And I believe Decimal's __float__ operation is a 'best effort' kind of
thing, so I have no problem with Rationals working the same way.


Actually, I suggested that:

float() + Rational() returns float

You're suggesting that the implicit conversion to float not happen
here, and the user be forced to cast it to float? And you're saying
Decimal does it that way.[

That's good enough for me.

<mike
--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Jul 18 '05 #21
Mike Meyer wrote:
Actually, I suggested that:

float() + Rational() returns float

You're suggesting that the implicit conversion to float not happen
here, and the user be forced to cast it to float? And you're saying
Decimal does it that way.[


Yup.

I had another look at PEP 327 (the section on implicit construction) and the
reasoning that got us to that behaviour wasn't quite what I thought. However, I
think the point still holds for Rational - the conversion often won't be exact
in either direction, so it's OK for Python to ask the programmer to confirm that
they really want to make the conversion.

I think adding subsections modelled on PEP 327's "Explicit construction",
"Implicit construction" and "Python usability" would be a big plus for the new
Rational PEP. The layout Facundo used makes it obvious that issues of playing
well with other types have been considered properly.

Cheers,
Nick.

--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #22

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

20 posts views Thread by Mike Meyer | last post: by
2 posts views Thread by Brian van den Broek | last post: by
18 posts views Thread by Lie | last post: by
135 posts views Thread by robinsiebler | last post: by
5 posts views Thread by anumliaqat | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.