# About Rational Number (PEP 239/PEP 240)

L

#### Lie

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.

M

#### mensanator

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.

L

#### Lie

<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).

F

#### Fredrik Johansson

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

L

#### Lie

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.

A

#### Arnaud Delobelle

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.

G

#### greg

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.

S

#### Steven D'Aprano

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.
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.

G

#### George Sakkis

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

D

#### Dennis Lee Bieber

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: (e-mail address removed))
HTTP://www.bestiaria.com/

S

#### Steven D'Aprano

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:
False

D

#### Dennis Lee Bieber

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:

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: (e-mail address removed))
HTTP://www.bestiaria.com/

L

#### Lie

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.

S

#### Steven D'Aprano

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.

A

#### Aahz

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.

M

#### Mel

Steven said:
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

G

#### Gabriel Genellina

[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.

B

#### Brian Victor

Gabriel said:
[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.

D

#### Dennis Lee Bieber

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: (e-mail address removed))
HTTP://www.bestiaria.com/

D

#### Dan Upton

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.