# About Rational Number (PEP 239/PEP 240)

Discussion in 'Python' started by Lie, Dec 15, 2007.

1. ### LieGuest

I'm very surprised actually, to see that Python rejected the use of
fractional/rational numbers. However, when I read the PEP, I know
exactly why the proposal was rejected: People compared fractions with
integers, while it should be more fairly compared to floats.

Arguments against:
- When I use the result of / as a sequence index, it's usually an
error which should not be hidden by making the program working for
some data, since it will break for other data.
----> In Python 3 (and 2 w/ __future__), the / operator would always
return floats, and floats is invalid as sequence index, even if the
value of the float is whole. Since fractions is created with the /
operator on two integers, the behavior of fractions should mimics
float. So putting fractional type as sequence index should always be
considered as error (exception), a behavior consistent with floats.
Thus, the arguments specified above has turned invalid, at least in
Python 3.
- (this assumes the same type for them Int is a good type in itself,
not to be mixed with rationals. The fact that something is an integer
should be expressible as a statement about its type. Many operations
require ints and don't accept rationals. It's natural to think about
----> I agree, ints shouldn't be mixed with rationals. But floats
could. This argument is the main reason why I said most people
compared rational with integers. Many operations that requires ints
and don't accept rationals also don't accept floats.

Other arguments:
- Slow: Doing addition and subtraction in fractions sure is expensive,
but doing division (the heaviest arithmetic operation) is extremely
fast in fractional numbers compared to in floating numbers. It is
clear that doing two integer multiplication and switching numerator-
denominator is much faster than doing a single float division.
- Memory Intensive: To represent 1/3 to infinite accuracy requires two-
integer-space (theoretically, 2 bytes). There are some numbers that
are hard to represent in fractions, yes, but in general those numbers
could be represented using two-long-space (variable-width longs). And
whenever accuracy isn't that important, it could be possible to create
a method that would lossily approximate the current fraction to an
acceptable length. Anyway, most computers nowadays is packed with
gigantic memory, why bother with such a small issue.
- Rationals must present themselves as decimal floats or it'll be
confusing: There will be no confusion in a good written code.
Progammers that writes good code would always use the 'behind-the-
scene' number, they wouldn't convert a previously 'string'ed number
back into calculation. And a convention can be created to represent a
fraction in a single line output (like * for multiplication, / for
division, they don't exist in paper maths) that would completely
eliminate any confusion of the user (well informed about the
convention, most people that never used computer before often tried to
use x and : to represent mult and div), even when the fractional
number is outputted to the foreground UI.

Lie, Dec 15, 2007

2. ### Guest

On Dec 15, 2:00 pm, Lie <> wrote:
> I'm very surprised actually, to see that Python rejected the use of
> fractional/rational numbers. However, when I read the PEP, I know
> exactly why the proposal was rejected: People compared fractions with
> integers, while it should be more fairly compared to floats.

Pretty lame reasoning, isn't it?

I use the rationals from the gmpy module very
successfully.

All these arguments that follow are just silly.

>
> Arguments against:
> - When I use the result of / as a sequence index, it's usually an
> error which should not be hidden by making the program working for
> some data, since it will break for other data.
> ----> In Python 3 (and 2 w/ __future__), the / operator would always
> return floats, and floats is invalid as sequence index, even if the
> value of the float is whole. Since fractions is created with the /
> operator on two integers, the behavior of fractions should mimics
> float. So putting fractional type as sequence index should always be
> considered as error (exception), a behavior consistent with floats.
> Thus, the arguments specified above has turned invalid, at least in
> Python 3.
> - (this assumes the same type for them Int is a good type in itself,
> not to be mixed with rationals. The fact that something is an integer
> should be expressible as a statement about its type. Many operations
> require ints and don't accept rationals. It's natural to think about
> them as about different types.
> ----> I agree, ints shouldn't be mixed with rationals. But floats
> could. This argument is the main reason why I said most people
> compared rational with integers. Many operations that requires ints
> and don't accept rationals also don't accept floats.
>
> Other arguments:
> - Slow: Doing addition and subtraction in fractions sure is expensive,
> but doing division (the heaviest arithmetic operation) is extremely
> fast in fractional numbers compared to in floating numbers. It is
> clear that doing two integer multiplication and switching numerator-
> denominator is much faster than doing a single float division.
> - Memory Intensive: To represent 1/3 to infinite accuracy requires two-
> integer-space (theoretically, 2 bytes). There are some numbers that
> are hard to represent in fractions, yes, but in general those numbers
> could be represented using two-long-space (variable-width longs). And
> whenever accuracy isn't that important, it could be possible to create
> a method that would lossily approximate the current fraction to an
> acceptable length. Anyway, most computers nowadays is packed with
> gigantic memory, why bother with such a small issue.
> - Rationals must present themselves as decimal floats or it'll be
> confusing: There will be no confusion in a good written code.
> Progammers that writes good code would always use the 'behind-the-
> scene' number, they wouldn't convert a previously 'string'ed number
> back into calculation. And a convention can be created to represent a
> fraction in a single line output (like * for multiplication, / for
> division, they don't exist in paper maths) that would completely
> eliminate any confusion of the user (well informed about the
> convention, most people that never used computer before often tried to
> use x and : to represent mult and div), even when the fractional
> number is outputted to the foreground UI.

, Dec 15, 2007

3. ### LieGuest

<cont.>
The easiest implementation of using fractional datatype is probably to
add a new operator. Some scientific calculators provide a special
operator to signify a fraction (somewhat on the shape of a small L in
mine) and I strongly believe that their internal calculation probably
used fractions even when regular division is used, only when the
calculator have difficulties using fraction (like calculating sin/cos/
tan function) or the screen is not wide enough to represent the
fraction would it use regular division.

Python implemented complex numbers, why not fractions?

Random ramble past here:
Actually, my vision would be not only fractions, but also rooted
number (square root, cube root, etc), it could be possible to
implement a type where a number consist of a rooted number times a
multiplier plus a variable [a + b * root(c, d)]. But I guess this
would be extremely complex and it requires nesting, probably very slow
if implementation isn't good. The advantage of using such is much
faster operations, as long as str() is not called. This actually
reflects my way of doing paper math, I save the lossy operations
(float division, root, trigonometric function) until the very end of
calculation (I'm not fundamentalist though, so compromise sometimes is
done here and there).

Lie, Dec 15, 2007
4. ### Fredrik JohanssonGuest

On Dec 15, 2007 10:05 PM, Lie <> wrote:
> Random ramble past here:
> Actually, my vision would be not only fractions, but also rooted
> number (square root, cube root, etc), it could be possible to
> implement a type where a number consist of a rooted number times a
> multiplier plus a variable [a + b * root(c, d)]. But I guess this
> would be extremely complex and it requires nesting, probably very slow
> if implementation isn't good. The advantage of using such is much
> faster operations, as long as str() is not called. This actually
> reflects my way of doing paper math, I save the lossy operations
> (float division, root, trigonometric function) until the very end of
> calculation (I'm not fundamentalist though, so compromise sometimes is
> done here and there).

You're looking for a computer algebra system. Try sympy:

Fredrik

Fredrik Johansson, Dec 15, 2007
5. ### LieGuest

On Dec 16, 4:55 am, "Fredrik Johansson" <>
wrote:
> On Dec 15, 2007 10:05 PM, Lie <> wrote:
>
> > Random ramble past here:
> > Actually, my vision would be not only fractions, but also rooted
> > number (square root, cube root, etc), it could be possible to
> > implement a type where a number consist of a rooted number times a
> > multiplier plus a variable [a + b * root(c, d)]. But I guess this
> > would be extremely complex and it requires nesting, probably very slow
> > if implementation isn't good. The advantage of using such is much
> > faster operations, as long as str() is not called. This actually
> > reflects my way of doing paper math, I save the lossy operations
> > (float division, root, trigonometric function) until the very end of
> > calculation (I'm not fundamentalist though, so compromise sometimes is
> > done here and there).

>
> You're looking for a computer algebra system. Try sympy:http://code.google.com/p/sympy/
>
> Fredrik

Yeah, that's why I consider them too complex for being included as a
core of a general programming language like Python. Nevertheless,
fraction datatype _IS_ elementary enough to be included as core
language feature.

Lie, Dec 15, 2007
6. ### Arnaud DelobelleGuest

On Dec 15, 10:38 pm, Lie <> wrote:
[...]
>
> Yeah, that's why I consider them too complex for being included as a
> core of a general programming language like Python. Nevertheless,
> fraction datatype _IS_ elementary enough to be included as core
> language feature.

Rationals are not that simple.

* Unless you are working under very controlled conditions, rationals
very quickly grow enormous numerators and denominators, hence
require arbitrary precision integers (which, I concede, are part of
Python).

* In order to have a canonical representation of integers, they need
to be kept in normalised form.

* Nobody uses big fractions apart from mathematicians (and maybe
bookmakers?).

* Having yet another numerical type would make it difficult what
type to expect from a calculation.

--
Arnaud

Arnaud Delobelle, Dec 15, 2007
7. ### gregGuest

I think the main objection to rationals is that extensive
computation with them tends to result in numbers requiring
larger and larger amounts of storage. I believe that ABC
made routine use of rationals, and this caused programs
to get bogged down for no apparent reason, as rationals
were being used behind the scenes when people didn't
realise it.

So while rationals might be useful to have available for
some things, you should have to explicitly ask for them.
Returning rationals from '/' applied to integers would
be a bad idea, for example.

--
Greg

greg, Dec 15, 2007
8. ### Steven D'ApranoGuest

On Sat, 15 Dec 2007 15:44:26 -0800, Arnaud Delobelle wrote:

> Rationals are not that simple.
>
> * Unless you are working under very controlled conditions, rationals
> very quickly grow enormous numerators and denominators, hence require
> arbitrary precision integers (which, I concede, are part of Python).

Come now. Rationals aren't living things that grow if you sit them in the
corner and provide them air and light. Whether the numerator and
denominator grow depends on what you do with them. If you wish to say
that they *can* grow enormous numerators and denominators, I won't argue,
but implying that *must* and will *always* grow is misleading. It's pure
propaganda.

And if they do... well, longs can also "quickly grow enormous". That
hasn't stopped Python integrating ints and longs. The programmer is
expected to deal with it. Integrating floats and rationals isn't even on
the table for discussion. Anyone using rationals is making a conscious
choice to do so and can deal with the consequences.

> * In order to have a canonical representation of integers, they need to
> be kept in normalised form.

Oh noes! Not normalised form!!!

Is this supposed to be an objection?

> * Nobody uses big fractions apart from mathematicians (and maybe
> bookmakers?).

Putting the cart before the horse. Nobody uses rationals because
rationals aren't available!

Nobody uses complex numbers except for mathematicians, and maybe a few
electrical engineers, and they're a built in. Nobody uses math functions
like sin and cos except for mathematicians and engineers, and they're
available.

The Forth programming language didn't even support floating point for
many years. Programmers were expected to use the equivalent of rationals
using integers. This was very successful, and avoided the gotchas that
you get with floats. For example, with floats it is unavoidable to have
unintuitive results like (x + y) - x != y and it isn't even very hard to
find an example.

>>> 3.1 + 0.7 - 3.1 == 0.7

False

Such a bizarre result shouldn't happen with any non-buggy rational
representation:

31/10 + 7/10 - 31/10 => 38/10 - 31/10 => 7/10

In the real world, people use fractions all the time, e.g. plumbers. (Not
that I'm expecting plumbers to start taking laptops out to the building
site in order to calculate pipe sizes.)

> * Having yet another numerical type would make it difficult what type to
> expect from a calculation.

I simply don't believe that at all. It's not like calculations will
suddenly start returning rationals unexpectedly, any more than they
suddenly started returning Decimals unexpectedly.

I find it bizarre that the simple to implement, simple to understand
rational data type was rejected while the hard to implement, hard to
understand Decimal was accepted.

--
Steven

Steven D'Aprano, Dec 16, 2007
9. ### George SakkisGuest

On Dec 15, 6:52 pm, greg <> wrote:

> So while rationals might be useful to have available for
> some things, you should have to explicitly ask for them.
> Returning rationals from '/' applied to integers would
> be a bad idea, for example.

From my reading of the PEP, it doesn't suggest such automatic
coercions (neither rejects them explicitly though). Given the huge
discussions about integer vs true division, it would be very
controversial to suggest implicit rational division.

Regardless, a builtin (or at least standard library) rational type
would be nice to have. Of course folks that *really need* rationals
are already using some 3rd party library, but for the rest of us it
would be an improvement in several cases where currently floats are
used, just like the motivation for Decimals. Only difference seems to
be that there aren't so many or compelling use cases for rationals as
for decimals (mainly money counting).

George

George Sakkis, Dec 16, 2007
10. ### Dennis Lee BieberGuest

On Sun, 16 Dec 2007 00:42:56 -0000, Steven D'Aprano
<> declaimed the following in
comp.lang.python:

> In the real world, people use fractions all the time, e.g. plumbers. (Not
> that I'm expecting plumbers to start taking laptops out to the building
> site in order to calculate pipe sizes.)
>

Piping tends to come in a limited range of discrete diameters, with
a slew of adapters to convert from one to another. As such, they fit
more in the Ada "fixed point" system or can be treated as a scaled
integer... One does not find random pipe diameters.
--
Wulfraed Dennis Lee Bieber KD6MOG

HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: )
HTTP://www.bestiaria.com/

Dennis Lee Bieber, Dec 16, 2007
11. ### Steven D'ApranoGuest

On Sat, 15 Dec 2007 17:42:26 -0800, Dennis Lee Bieber wrote:

> On Sun, 16 Dec 2007 00:42:56 -0000, Steven D'Aprano
> <> declaimed the following in
> comp.lang.python:
>
>> In the real world, people use fractions all the time, e.g. plumbers.
>> (Not that I'm expecting plumbers to start taking laptops out to the
>> building site in order to calculate pipe sizes.)
>>

> Piping tends to come in a limited range of discrete diameters, with
> a slew of adapters to convert from one to another. As such, they fit
> more in the Ada "fixed point" system or can be treated as a scaled
> integer... One does not find random pipe diameters.

Yes, but my point (badly put, I admit) was that people find fractions far
easier to work with than they find floating point numbers. And with any
rational data type worth the name, you simply should never get anything
as unintuitive as this:

>>> from __future__ import division
>>> 4/10 + 2/10 == 6/10

False

--
Steven

Steven D'Aprano, Dec 16, 2007
12. ### Dennis Lee BieberGuest

On Sun, 16 Dec 2007 06:09:06 -0000, Steven D'Aprano
<> declaimed the following in
comp.lang.python:

> Yes, but my point (badly put, I admit) was that people find fractions far
> easier to work with than they find floating point numbers. And with any
> rational data type worth the name, you simply should never get anything
> as unintuitive as this:
>
> >>> from __future__ import division
> >>> 4/10 + 2/10 == 6/10

> False

Which only seems to me to prove that having integer division return
a floating value is a mistake <G> My background with mostly ancient
languages (FORTRAN) reads that and sees "0 + 0 == 0", and "4.0/10.0 +
2.0/10.0 == 6.0/10.0" automatically makes me leery...

--
Wulfraed Dennis Lee Bieber KD6MOG

HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: )
HTTP://www.bestiaria.com/

Dennis Lee Bieber, Dec 16, 2007
13. ### LieGuest

> Rationals are not that simple.

So do complex number, in fact most people are much more familiar with
rationals/fractions than with complex number. And notice that I don't
use the word simple, I use the word elementary. Elementary doesn't
always means simple (although it usually is), but rather it emphasizes
on it being essential and being a basic building block for other
things.

And if you think about it, floating numbers aren't that simple either.
It only seems simple because it's implemented natively in the
hardware, but I'm sure the engineers creating them have a heated
discussion when they first try to implement it. Remember the
discussion about Decimals? How many rounding methods are there?

> * Unless you are working under very controlled conditions, rationals
> very quickly grow enormous numerators and denominators, hence
> require arbitrary precision integers (which, I concede, are part of
> Python).

One part of the problem is solved (arbitrary length integers) another
problem is the growth of rationals. That could have easy workaround,
like a scientific calculator, by using a special operator to construct
a fractions, people would only _consciously_ use fractions, avoiding
unexpected return of fraction AND controlled environment for using
fraction. It's also possible to have lossy_simplify(n[, acc]) method
for calculations that need rationals but don't need such accuracy (in
that case, perhaps float could be a better substitute).

> * In order to have a canonical representation of integers, they need
> to be kept in normalised form.

There are methods to simplify fractions and there are addition,
subtraction, division, multiplication, etc can be made to
automatically returns the most simple form.
[btw, off topic, in music, isn't 1/4 and 2/8 different? I'm not very
keen of music though, so correct me if I'm wrong.]

> * Having yet another numerical type would make it difficult what
> type to expect from a calculation.

There is a simple rule of thumb:
If a (built-in) method receives floats returns floats, else returns
fractions << Please don't take me too literally here, apply some
compromises.
The rationale is simple: Float's can't be turned easily into fraction,
while the otherwise involves only a simple true division.

> Which only seems to me to prove that having integer division return
> a floating value is a mistake

Oh no, it's not a mistake. Only IEEE's floating point standard isn't
sufficient to cope with exact arithmetic. Another reason to use
fractions.

> So while rationals might be useful to have available for
> some things, you should have to explicitly ask for them.
> Returning rationals from '/' applied to integers would
> be a bad idea, for example.

> From my reading of the PEP, it doesn't suggest such automatic
> coercions (neither rejects them explicitly though). Given the huge
> discussions about integer vs true division, it would be very
> controversial to suggest implicit rational division.

Which I agree, implicit rational division would be evil. People should
explicitly use fractions, using a special division operators, just
like calculators (although mine seems to always use fractions 'behind-
the-scenes' whenever possible, but on presenting them to the user it
does the rule of thumbs I mentioned).

> Regardless, a builtin (or at least standard library) rational type
> would be nice to have. Of course folks that *really need* rationals
> are already using some 3rd party library, but for the rest of us it
> would be an improvement in several cases where currently floats are
> used, just like the motivation for Decimals. Only difference seems to
> be that there aren't so many or compelling use cases for rationals as
> for decimals (mainly money counting).

People have, for ages used floating numbers in calculation on
occasions where it shouldn't be used, and that's a really bad practice
and even prominent (paper) mathematician are accustomed to such
practice. Floating numbers involves rounding and continued use of them
would make the value wanders off far away.

Lie, Dec 16, 2007
14. ### Steven D'ApranoGuest

On Sat, 15 Dec 2007 22:20:22 -0800, Dennis Lee Bieber wrote:

> On Sun, 16 Dec 2007 06:09:06 -0000, Steven D'Aprano
> <> declaimed the following in
> comp.lang.python:
>
>> Yes, but my point (badly put, I admit) was that people find fractions
>> far easier to work with than they find floating point numbers. And with
>> any rational data type worth the name, you simply should never get
>> anything as unintuitive as this:
>>
>> >>> from __future__ import division
>> >>> 4/10 + 2/10 == 6/10

>> False

>
> Which only seems to me to prove that having integer division return
> a floating value is a mistake <G>

What integer division? It's floating point division. The / operator
creates floats. If I wanted integer division, I would have used //.

> My background with mostly ancient
> languages (FORTRAN) reads that and sees "0 + 0 == 0",

With some floating point implementations, one can find values such that
x == 0.0 and y == 0.0 but x + y != 0.0.

> and "4.0/10.0 + 2.0/10.0 == 6.0/10.0" automatically makes me leery...

*shrug*

That's the whole point. Floating point math is weird. Rationals are not.
Using floats when you actually need rationals is dangerous.

--
Steven

Steven D'Aprano, Dec 16, 2007
15. ### AahzGuest

In article <>,
George Sakkis <> wrote:
>
>Regardless, a builtin (or at least standard library) rational type
>would be nice to have. Of course folks that *really need* rationals
>are already using some 3rd party library, but for the rest of us it
>would be an improvement in several cases where currently floats are
>used, just like the motivation for Decimals. Only difference seems to
>be that there aren't so many or compelling use cases for rationals as
>for decimals (mainly money counting).

You've precisely hit on the problem: previous discussion about rationals
has bogged down because proponents insisted on making it a built-in type
rather than a library. If a PEP were submitted with code for a library,
there would be little trouble getting it accepted -- just like Decimal.

Even now, after a couple of releases with Decimal in the library, there
remains much opposition to a Decimal built-in, not even talking about
Decimal literals.
--
Aahz () <*> http://www.pythoncraft.com/

"Typing is cheap. Thinking is expensive." --Roy Smith

Aahz, Dec 16, 2007
16. ### MelGuest

Steven D'Aprano wrote:

> Yes, but my point (badly put, I admit) was that people find fractions far
> easier to work with than they find floating point numbers.

I'm not so sure. I got caught by the comic XKCD's
infinite-resistor-grid thing, and simplified it to a ladder network --
call it L -- made up of 2 1-ohm resistors in series with a 1-ohm
resistor paralleled by L. Simulating this -- assuming an arbitrary
endpoint with resistance 3 -- well, it takes a little thought to
decide that 11/15 < 3/4, and a lot more to decide the same thing for
153/209 and thus decide whether the series is coming or going.

Then when you work out the right answer from

L = 2 + (L / (L+1))

as floats, and at far greater expense.

I wrote a Rational class back when I was learning to do these things
in Python, and it was actually pretty easy: a dash of GCD, a pinch of
partial fractions, and a lot of following the Python Reference Manual.
It eventually worked as advertised, but I haven't used it since.
It could stand to be updated to use the __new__ method and produce
genuinely immutable instances, if I could find the source.

Mel.
And with any
> rational data type worth the name, you simply should never get anything
> as unintuitive as this:
>
>>>> from __future__ import division
>>>> 4/10 + 2/10 == 6/10

> False
>
>
>

Mel, Dec 16, 2007
17. ### Gabriel GenellinaGuest

[OT] Fractions on musical notation

On 16 dic, 06:40, Lie <> wrote:

> [btw, off topic, in music, isn't 1/4 and 2/8 different? I'm not very
> keen of music though, so correct me if I'm wrong.]

As a time signature 1/4 has no sense, but 3/4 and 6/8 are different
things. In the standard musical notation both numbers are written one
above the other, and no "division" line is used. Note that they just
*look* like a fraction when written in text form, like here, because
it's not easy to write one above the other.
3/4 is read as "three by four", not "three quarters" -at least in my
country- so there is even less confussion.

--
Gabriel Genellina

Gabriel Genellina, Dec 17, 2007
18. ### Brian VictorGuest

Re: [OT] Fractions on musical notation

Gabriel Genellina wrote:
> On 16 dic, 06:40, Lie <> wrote:
>
>> [btw, off topic, in music, isn't 1/4 and 2/8 different? I'm not very
>> keen of music though, so correct me if I'm wrong.]

> As a time signature 1/4 has no sense

Actually, I'm playing a show right now that has a one beat vamp. It's a
single repeated measure in 1/4 time.

To addres the real point, though, I don't think of a time signature as a
rational number, although it correctly reflects what portion of a whole
note can be found within a measure. I consider it to have two separate
pieces of information: the length of the beat and the number of those
beats per bar. When I've written code to represent music I have used
rationals to represent when something occurs, but a different structure
to represent time signatures.

--
Brian

Brian Victor, Dec 17, 2007
19. ### Dennis Lee BieberGuest

Re: [OT] Fractions on musical notation

On Sun, 16 Dec 2007 16:21:28 -0800 (PST), Gabriel Genellina
<> declaimed the following in comp.lang.python:

>
> As a time signature 1/4 has no sense, but 3/4 and 6/8 are different
> things. In the standard musical notation both numbers are written one
> above the other, and no "division" line is used. Note that they just
> *look* like a fraction when written in text form, like here, because
> it's not easy to write one above the other.
> 3/4 is read as "three by four", not "three quarters" -at least in my
> country- so there is even less confussion.

Let me guess... Your country also uses things like demiquavers?

Since the US, at least, uses whole/half/quarter/eighth/sixteenth...
notes, three-quarter and six-eight time falls out...
--
Wulfraed Dennis Lee Bieber KD6MOG

HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: )
HTTP://www.bestiaria.com/

Dennis Lee Bieber, Dec 17, 2007
20. ### Dan UptonGuest

Re: [OT] Fractions on musical notation

> Since the US, at least, uses whole/half/quarter/eighth/sixteenth...
> notes, three-quarter and six-eight time falls out...

I don't think this is technically true, but I've never been able to
tell the difference.

Dan Upton, Dec 17, 2007