By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
425,478 Members | 1,374 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 425,478 IT Pros & Developers. It's quick & easy.

Using fractions instead of floats

P: n/a
I was doing some programming in Python, and the idea came to my mind:
using fractions instead of floats when doing 2/5.

The problem arises when you try to represent some number, like 0.4 in
a float. It will tell you that it's equal to 0.40000000000000002.
"This is easy to fix", you may say. "You just use the decimal.Decimal
class!". Well, firsly, there would be an excess of typing I would need
to do to calculate 0.4+0.6:

from decimal import Decimal
print Decimal("0.4")+Decimal("0.6")

Secondly, what happens if I need to sum 1/3 and 0.4? I could use
Decimal to represent 0.4 precisely, but what about 1/3? Sure, I could
use _another_ class which works in a base (binary, decimal, octal,
hexadecimal) in which 1/3 can be represented exactly... Not to mention
the problem of operating with those two different classes...

So the solution I think is using a fraction type/class, similar to the
one found in Common Lisp. If you have used CLisp before, you only need
to type:
(+ 1/3 6/10)
to get the exact result. (Yes, I also hate the (operator arg1 arg2)
syntax, but it's just an example). I would like to have something
similar in Python, in which dividing two numbers gives you a fraction,
instead of an integer (python 2.x) or a float (decided for python
3.x).

an implementation could be like this:
class frac(object): # PS: This (object) thing will be removed in
python 3.0, right?
def __init__(self, numerator, denominator):
pass
def __add__(self, other):
pass
#...

(I have an implementation of the frac class done (this meaning, it
works for me), and although it's pretty dirty, I'd be happy to post it
here if you want it.)

My idea, in summary would be that this python shell session is true:
>>5/2
2 1/2
>>f = 5/2
f.__class__
<type 'frac'>
>># or <class 'frac'>
(0.6).__class__ # Treat decimal literals as fractions, so that...
<type 'frac'>
>>1/3+0.6
14/15
>># That was easy. ;)
I would like to get some feedback on this idea. Has this been posted
before? If so, was it rejected? and for what?
Also, I would like to know if you have improvements on the initial
design, and if it would be appropiate to send it as a PEP.

Oct 1 '07 #1
Share this Question
Share on Google+
32 Replies


P: n/a
andresj <an**********@gmail.comwrites:
The problem arises when you try to represent some number, like 0.4 in
a float.
Which is really a specific case of the general problem that, for any
given number base, some non-integer numbers cannot be exactly
represented as fractions.
Secondly, what happens if I need to sum 1/3 and 0.4? I could use
Decimal to represent 0.4 precisely, but what about 1/3?
What about the sum of π (pi) and √2 (sqrt(2))?
So the solution I think is using a fraction type/class
As explained above, a fractional-number class only shifts the "exact
representation" problem, it doesn't solve it.

--
\ "Facts do not cease to exist because they are ignored." -- |
`\ Aldous Huxley |
_o__) |
Ben Finney
Oct 1 '07 #2

P: n/a
On Sep 30, 6:48 pm, Ben Finney <bignose+hates-s...@benfinney.id.au>
wrote:
andresj <andres.j....@gmail.comwrites:
The problem arises when you try to represent some number, like 0.4 in
a float.

Which is really a specific case of the general problem that, for any
given number base, some non-integer numbers cannot be exactly
represented as fractions.
Yes. That's what I meant to say, by giving an example.
Secondly, what happens if I need to sum 1/3 and 0.4? I could use
Decimal to represent 0.4 precisely, but what about 1/3?

What about the sum of (pi) and 2 (sqrt(2))?
Mm... To be honest I hadn't thought of that in the moment I wrote the
last post...
But I think then, that I'll be more specific, so that my proposal only
deals with *rational numbers*, not irrationals.
>
So the solution I think is using a fraction type/class

As explained above, a fractional-number class only shifts the "exact
representation" problem, it doesn't solve it.
I don't understand completely what you said, but I think you are
saying that it doesn't solve the problem with irrational numbers.
Which is exactly what this proposal doesn't solve. (Mainly because I
do not know of any way of doing it in "normal" math).

(While I write this, my mind reminds me of operating with roots " 2
(sqrt(2))", which I think could be solved in another similar way,
although it has some more specific use cases... But in any case,
that's not in the scope of this proposal, as they are irrational
numbers.)

Oct 1 '07 #3

P: n/a
On Sep 30, 8:35?pm, andresj <andres.j....@gmail.comwrote:
I was doing some programming in Python, and the idea came to my mind:
using fractions instead of floats when doing 2/5.

The problem arises when you try to represent some number, like 0.4 in
a float. It will tell you that it's equal to 0.40000000000000002.
"This is easy to fix", you may say. "You just use the decimal.Decimal
class!". Well, firsly, there would be an excess of typing I would need
to do to calculate 0.4+0.6:

from decimal import Decimal
print Decimal("0.4")+Decimal("0.6")

Secondly, what happens if I need to sum 1/3 and 0.4? I could use
Decimal to represent 0.4 precisely, but what about 1/3? Sure, I could
use _another_ class which works in a base (binary, decimal, octal,
hexadecimal) in which 1/3 can be represented exactly... Not to mention
the problem of operating with those two different classes...

So the solution I think is using a fraction type/class, similar to the
one found in Common Lisp. If you have used CLisp before, you only need
to type:
(+ 1/3 6/10)
to get the exact result. (Yes, I also hate the (operator arg1 arg2)
syntax, but it's just an example). I would like to have something
similar in Python, in which dividing two numbers gives you a fraction,
instead of an integer (python 2.x) or a float (decided for python
3.x).

an implementation could be like this:
class frac(object): # PS: This (object) thing will be removed in
python 3.0, right?
def __init__(self, numerator, denominator):
pass
def __add__(self, other):
pass
#...

(I have an implementation of the frac class done (this meaning, it
works for me), and although it's pretty dirty, I'd be happy to post it
here if you want it.)

My idea, in summary would be that this python shell session is true:
>5/2
2 1/2
>f = 5/2
f.__class__
<type 'frac'>
># or <class 'frac'>
(0.6).__class__ # Treat decimal literals as fractions, so that...
<type 'frac'>
>1/3+0.6
14/15
># That was easy. ;)

I would like to get some feedback on this idea. Has this been posted
before? If so, was it rejected? and for what?
Also, I would like to know if you have improvements on the initial
design, and if it would be appropiate to send it as a PEP.
The gmpy module has unlimited precision rationals.
Works pretty good, too.

Oct 1 '07 #4

P: n/a
On Sep 30, 9:35 pm, andresj <andres.j....@gmail.comwrote:
I was doing some programming in Python, and the idea came to my mind: using fractions instead of floats when doing 2/5.
(...)
I would like to get some feedback on this idea. Has this been posted
before? If so, was it rejected? and for what?
Is internet down today ?

http://pypi.python.org/pypi/clnum/1.2
http://www.python.org/dev/peps/pep-0239/

George

Oct 1 '07 #5

P: n/a
PS: Sorry, George Sakkis, for the double emailing... I forgot to add
python-list in the To: field the first time. :)

Haha. Ok. Thank you for pointing me to those links :). I hadn't
thought of searching for the word 'rational' instead of 'decimal'...
>From what I've read, seems that the principal reason for rejecting the
PEP is that there was not much need (enthusiasm)... Well, then I have
a question: Is there a way to make 5/2 return something other than an
integer? I can do:
class int(int):
def __add__(self, other):
pass
but that will only work if I do int(5)/int(2)...

(setting __builtin__.int=int doesn't work, either)

What I'd like is to be able to implement what I put in the proposal,
as I don't think it's a really big language change...

On 9/30/07, George Sakkis <ge***********@gmail.comwrote:
On Sep 30, 9:35 pm, andresj <andres.j....@gmail.comwrote:
I was doing some programming in Python, and the idea came to my mind: using fractions instead of floats when doing 2/5.
(...)
I would like to get some feedback on this idea. Has this been posted
before? If so, was it rejected? and for what?

Is internet down today ?

http://pypi.python.org/pypi/clnum/1.2
http://www.python.org/dev/peps/pep-0239/
Oct 1 '07 #6

P: n/a
En Sun, 30 Sep 2007 23:36:23 -0300, George Sakkis
<ge***********@gmail.comescribi�:
On Sep 30, 9:35 pm, andresj <andres.j....@gmail.comwrote:
>I was doing some programming in Python, and the idea came to my mind:
using fractions instead of floats when doing 2/5.
(...)
I would like to get some feedback on this idea. Has this been posted
before? If so, was it rejected? and for what?

Is internet down today ?

http://pypi.python.org/pypi/clnum/1.2
http://www.python.org/dev/peps/pep-0239/
And gmpy: http://www.aleax.it/gmpy.html

--
Gabriel Genellina

Oct 1 '07 #7

P: n/a

"Andres Riofrio" <an**********@gmail.comwrote in message
news:52*****************************************@m ail.gmail.com...
| a question: Is there a way to make 5/2 return something other than an
| integer?
>>from __future__ import division
1/2
0.5
>>5/2
2.5

tjr

Oct 1 '07 #8

P: n/a
En Mon, 01 Oct 2007 00:10:05 -0300, Andres Riofrio
<an**********@gmail.comescribi�:
From what I've read, seems that the principal reason for rejecting the
PEP is that there was not much need (enthusiasm)... Well, then I have
a question: Is there a way to make 5/2 return something other than an
integer? I can do:
class int(int):
def __add__(self, other):
pass
but that will only work if I do int(5)/int(2)...
I'm afraid not. But if you are crazy enough you can preprocess your source
using something similar to the tokenize example
<http://docs.python.org/lib/module-tokenize.html>

--
Gabriel Genellina

Oct 1 '07 #9

P: n/a
Andres Riofrio a crit :
<zip>
Well, then I have
a question: Is there a way to make 5/2 return something other than an
integer?
>>from __future__ import division
5/2
2.5
Oct 1 '07 #10

P: n/a
Gabriel Genellina <ga*******@yahoo.com.arwrote:
And gmpy: http://www.aleax.it/gmpy.html
And a concrete example
>>from gmpy import mpq
mpq(1,3)+mpq(0.4)
mpq(11,15)
>>mpq(1,3)+mpq(4,10)
mpq(11,15)
>>mpq(1,3)+mpq(6,10)
mpq(14,15)
>>mpq(1,3)+0.6
mpq(14,15)
>>mpq(5,2)
mpq(5,2)
>>mpq(1,3)*mpq(6,10)*mpq(4,10)+mpq(7,8)
mpq(191,200)
>>>
--
Nick Craig-Wood <ni**@craig-wood.com-- http://www.craig-wood.com/nick
Oct 1 '07 #11

P: n/a
On Sun, 30 Sep 2007 20:10:05 -0700, Andres Riofrio wrote:

[snip]
>>From what I've read, seems that the principal reason for rejecting the
PEP is that there was not much need (enthusiasm)... Well, then I have a
question: Is there a way to make 5/2 return something other than an
integer? I can do:
class int(int):
def __add__(self, other):
pass
but that will only work if I do int(5)/int(2)...

(setting __builtin__.int=int doesn't work, either)

What I'd like is to be able to implement what I put in the proposal, as
I don't think it's a really big language change...
[snip]

You could make up an example implementation by using fractionizing_int
(1) / fractionizing_int(3) (or whatever name you come up with).

I don't know of any particularly nice way to Just Let It Work anywhere in
python (perhaps some ugly byte code hacks, automatically wrapping ints).
So, you would have to implement it in C if you want to propose this for
CPython. And that's no 5 minute task, I guess.

Still, having this `int` behaviour working globally would include those
previously mentioned irrational numbers (but Pi is rational in any
visualization anyways, so FWIW that wouldn't be too much of a blockade).
But where would you put normal integer division then?
Introducing a new type seems best to me.

You could, as well, try to implement this in PyPy. If this would hit the
broad masses is another question, though. ;)

Regards,
stargaming
Oct 1 '07 #12

P: n/a
On Oct 1, 2:35 am, andresj <andres.j....@gmail.comwrote:

[snip Rational numbers in Python]
I would like to get some feedback on this idea. Has this been posted
before? If so, was it rejected? and for what?
Also, I would like to know if you have improvements on the initial
design, and if it would be appropiate to send it as a PEP.
As pointed out by others, implementations of rationals in Python
abound. Whereas there is a canonical representation of floats and ints
(and even longints) in the machine, it is not the case for rationals.
Moreover most programming tasks do not need rationals, so why burden
the language with them? If one needs them, there are perfectly
adequate modules to import (even though I, like many others I suspect,
have my own implementation in pure Python). Finally, arithmetic would
become very confusing if there were three distinct numeric types; it
already causes enough confusion with two!

--
Arnaud
Oct 1 '07 #13

P: n/a
On 2007-10-01, Arnaud Delobelle <ar*****@googlemail.comwrote:
Finally, arithmetic would become very confusing if there were
three distinct numeric types; it already causes enough
confusion with two!
Scheme says: It's not that bad.

--
Neil Cerutti
I am free of all prejudices. I hate everyone equally. --W. C. Fields
Oct 1 '07 #14

P: n/a
On Oct 1, 6:26 pm, Neil Cerutti <horp...@yahoo.comwrote:
On 2007-10-01, Arnaud Delobelle <arno...@googlemail.comwrote:
Finally, arithmetic would become very confusing if there were
three distinct numeric types; it already causes enough
confusion with two!

Scheme says: It's not that bad.
Scheme has prefix numeric operators, so that 1/2 is unambiguously (for
the interpreter and the user) a litteral for 'the fraction 1/2'. You
can't avoid the confusion in python, as binary operators are infix. Of
course, we could create a new kind of litteral. Let's see, / and //
are already operators, so why not use /// ? ;)

--
Arnaud
Oct 1 '07 #15

P: n/a
On Oct 1, 8:30 am, Nick Craig-Wood <n...@craig-wood.comwrote:
>>mpq(1,3)+0.6
mpq(14,15)
Golly! That's quite impressive. And more than a little bit magic as
well, since 0.6 is definitely not the same as 3/5. How on earth does
this work?

Richard

Oct 2 '07 #16

P: n/a
On Oct 1, 7:20 pm, richy...@gmail.com wrote:
On Oct 1, 8:30 am, Nick Craig-Wood <n...@craig-wood.comwrote:
>>mpq(1,3)+0.6
mpq(14,15)

Golly! That's quite impressive. And more than a little bit magic as
well, since 0.6 is definitely not the same as 3/5.
It's not? Since when?
>>print gmpy.mpq('0.6')
3/5
How on earth does this work?
The rationals are always reduced to lowest terms.
>
Richard

Oct 2 '07 #17

P: n/a
On Oct 1, 9:03 pm, "mensana...@aol.com" <mensana...@aol.comwrote:
On Oct 1, 7:20 pm, richy...@gmail.com wrote:
On Oct 1, 8:30 am, Nick Craig-Wood <n...@craig-wood.comwrote:
>>mpq(1,3)+0.6
mpq(14,15)
Golly! That's quite impressive. And more than a little bit magic as
well, since 0.6 is definitely not the same as 3/5.

It's not? Since when?
The 0.6 above is a floating point number, mathematically very close to
0.6 but definitely not equal to it, since 0.6 can't be represented
exactly as a float.

Oct 2 '07 #18

P: n/a

"andresj" <an**********@gmail.comwrote in message
news:11*********************@50g2000hsm.googlegrou ps.com...
|| I know from __future__ import division changes the behaivour to return
| floats instead of ints, but what I meant is to be able to implement a
| function (or class/method) which would return what _I_ want/decide.

When you define your own class, you can make any operator (on instances of
that class) mean anything you want. But to use such methonds, once
defined, you first have to make instances of that class using
classname(init data) or whatever.

There is no way to hijack int op int though.

tjr

Oct 2 '07 #19

P: n/a
On Oct 1, 8:17?pm, richy...@gmail.com wrote:
On Oct 1, 9:03 pm, "mensana...@aol.com" <mensana...@aol.comwrote:
On Oct 1, 7:20 pm, richy...@gmail.com wrote:
On Oct 1, 8:30 am, Nick Craig-Wood <n...@craig-wood.comwrote:
>>mpq(1,3)+0.6
mpq(14,15)
Golly! That's quite impressive. And more than a little bit magic as
well, since 0.6 is definitely not the same as 3/5.
It's not? Since when?

The 0.6 above is a floating point number, mathematically very close to
0.6 but definitely not equal to it, since 0.6 can't be represented
exactly as a float.
Oh, you mean something like this, right?
>>import gmpy
a = 0.6
a
0.59999999999999998

So, the rational should have 59999999999999998
in the neumerator and 100000000000000000 in the
denominator? But it doesn't
>>b = gmpy.mpq(a)
b
mpq(3,5)

Why do you suppose that is? For that matter, why
does
>>str(a)
'0.6'

give me an EXACT representation? Didn't you just
say it couldn't be represented exactly?

Which is correct,
>>str(a)
'0.6'

or
>>repr(a)
'0.59999999999999998'

?

How does gmpy make the conversion from float to rational?

Oct 2 '07 #20

P: n/a
On Sep 30, 7:35 pm, andresj <andres.j....@gmail.comwrote:
I was doing some programming in Python, and the idea came to my mind:
using fractions instead of floats when doing 2/5.
The core problem with rationals (other than the inability to handle
irrationals) is their tendency to require more and more memory as
calculations progress. This means they get mysteriously slower and
slower.

http://mail.python.org/pipermail/pyt...er/166630.html

My own "pet numeric type" is fixed point. You get as much precision
as you specify. Alas, 2/5 would likely result in 0. ;)

--
Adam Olsen, aka Rhamphoryncus

Oct 2 '07 #21

P: n/a
me********@aol.com wrote:
On Oct 1, 8:17?pm, richy...@gmail.com wrote:
>On Oct 1, 9:03 pm, "mensana...@aol.com" <mensana...@aol.comwrote:
>>On Oct 1, 7:20 pm, richy...@gmail.com wrote:
On Oct 1, 8:30 am, Nick Craig-Wood <n...@craig-wood.comwrote:
>>mpq(1,3)+0.6
mpq(14,15)
Golly! That's quite impressive. And more than a little bit magic as
well, since 0.6 is definitely not the same as 3/5.
It's not? Since when?
The 0.6 above is a floating point number, mathematically very close to
0.6 but definitely not equal to it, since 0.6 can't be represented
exactly as a float.

Oh, you mean something like this, right?
>>>import gmpy
a = 0.6
a
0.59999999999999998

So, the rational should have 59999999999999998
in the neumerator and 100000000000000000 in the
denominator?
Actually (5404319552844595 / 2**53) would be best.
But it doesn't
>>>b = gmpy.mpq(a)
b
mpq(3,5)

Why do you suppose that is?
For the same reason that str() does. See below.
For that matter, why
does
>>>str(a)
'0.6'

give me an EXACT representation?
It doesn't. It just rounds at a lower number of decimal places than is necessary
to faithfully represent the number. str() is intended to give friendly results,
not strictly correct ones. In this case it happens that float(str(0.6)) == 0.6,
but this is not guaranteed. For most numbers that a user or programmer might
enter, there will only be a relatively small amount of precision necessary, and
float(str(x)) == x will tend to hold. That's why it does this.
Didn't you just
say it couldn't be represented exactly?
Yup.
Which is correct,
>>>str(a)
'0.6'

or
>>>repr(a)
'0.59999999999999998'

?
The latter.
How does gmpy make the conversion from float to rational?
gmpy has a configurable transformation between floats and the internal
representation. I believe the default goes through str().

--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco

Oct 2 '07 #22

P: n/a
On 2007-10-01, Arnaud Delobelle <ar*****@googlemail.comwrote:
On Oct 1, 6:26 pm, Neil Cerutti <horp...@yahoo.comwrote:
>On 2007-10-01, Arnaud Delobelle <arno...@googlemail.comwrote:
Finally, arithmetic would become very confusing if there were
three distinct numeric types; it already causes enough
confusion with two!

Scheme says: It's not that bad.

Scheme has prefix numeric operators, so that 1/2 is
unambiguously (for the interpreter and the user) a litteral for
'the fraction 1/2'. You can't avoid the confusion in python, as
binary operators are infix. Of course, we could create a new
kind of litteral. Let's see, / and // are already operators,
so why not use /// ? ;)
But you wouldn't actually need a literal rational represention.

But I'm just playing Devil's Advocate here; I like rationals in
Scheme and Lisp, but I don't see a need for them in Python.

On the other hand, Python has had complex numbers a long time,
and it doesn't need those more than rationals, does it? My guess
is that it got complex numbers but not rationals because
rationals just aren't very efficient.

But as a programmer, I'm mostly just a data-twiddler, and don't
generally need either of those numeric type in my day-to-day
work. So I'm not the guy to ask. ;)

--
Neil Cerutti
I'm tired of hearing about money, money, money, money, money. I just want to
play the game, drink Pepsi, wear Reebok. --Shaquille O'Neal
Oct 2 '07 #23

P: n/a
On Oct 2, 12:42 pm, Neil Cerutti <horp...@yahoo.comwrote:
On 2007-10-01, Arnaud Delobelle <arno...@googlemail.comwrote:
Scheme has prefix numeric operators, so that 1/2 is
unambiguously (for the interpreter and the user) a litteral for
'the fraction 1/2'. You can't avoid the confusion in python, as
binary operators are infix. Of course, we could create a new
kind of litteral. Let's see, / and // are already operators,
so why not use /// ? ;)

But you wouldn't actually need a literal rational represention.
In which case rationals are better off in a module than in the
language!
But I'm just playing Devil's Advocate here; I like rationals in
Scheme and Lisp, but I don't see a need for them in Python.
On the other hand, Python has had complex numbers a long time,
and it doesn't need those more than rationals, does it? My guess
is that it got complex numbers but not rationals because
rationals just aren't very efficient.
Another guess could be that real numbers being closed under the four
arithmetic operations, there is no danger to accidentally step into
complex numbers. OTOH floats and rationals are two (conflicting) ways
of extending integers.
But as a programmer, I'm mostly just a data-twiddler, and don't
generally need either of those numeric type in my day-to-day
work. So I'm not the guy to ask. ;)
I use rationals a lot, and I don't want them in the language :)

--
Arnaud
Oct 2 '07 #24

P: n/a
On 2007-10-02, Arnaud Delobelle <ar*****@googlemail.comwrote:
On Oct 2, 12:42 pm, Neil Cerutti <horp...@yahoo.comwrote:
>On 2007-10-01, Arnaud Delobelle <arno...@googlemail.comwrote:
Scheme has prefix numeric operators, so that 1/2 is
unambiguously (for the interpreter and the user) a litteral for
'the fraction 1/2'. You can't avoid the confusion in python, as
binary operators are infix. Of course, we could create a new
kind of litteral. Let's see, / and // are already operators,
so why not use /// ? ;)

But you wouldn't actually need a literal rational represention.

In which case rationals are better off in a module than in the
language!
I was supposing that 1/2 would result in a rational number, which
would require language support, whether it's a literal rational
number or a division of two integer constants.
>But I'm just playing Devil's Advocate here; I like rationals
in Scheme and Lisp, but I don't see a need for them in Python.
>On the other hand, Python has had complex numbers a long time,
and it doesn't need those more than rationals, does it? My
guess is that it got complex numbers but not rationals because
rationals just aren't very efficient.

Another guess could be that real numbers being closed under the
four arithmetic operations, there is no danger to accidentally
step into complex numbers. OTOH floats and rationals are two
(conflicting) ways of extending integers.
You would have to adopt a few simple conversion rules, a la
Scheme. Inexact numbers are contagious, for example. It was
pretty shocking for a Scheme programmer to see the gmpy package
break that rule. ;)
I use rationals a lot, and I don't want them in the language :)
Fair enough.

--
Neil Cerutti
The pastor will preach his farewell message, after which the choir will sing,
"Break Forth Into Joy." --Church Bulletin Blooper
Oct 2 '07 #25

P: n/a
On Oct 2, 1:12 am, Robert Kern <robert.k...@gmail.comwrote:
mensana...@aol.com wrote:
On Oct 1, 8:17?pm, richy...@gmail.com wrote:
On Oct 1, 9:03 pm, "mensana...@aol.com" <mensana...@aol.comwrote:
>On Oct 1, 7:20 pm, richy...@gmail.com wrote:
On Oct 1, 8:30 am, Nick Craig-Wood <n...@craig-wood.comwrote:
>>mpq(1,3)+0.6
mpq(14,15)
Golly! That's quite impressive. And more than a little bit magic as
well, since 0.6 is definitely not the same as 3/5.
It's not? Since when?
The 0.6 above is a floating point number, mathematically very close to
0.6 but definitely not equal to it, since 0.6 can't be represented
exactly as a float.
Oh, you mean something like this, right?
>>import gmpy
a = 0.6
a
0.59999999999999998
So, the rational should have 59999999999999998
in the neumerator and 100000000000000000 in the
denominator?

Actually (5404319552844595 / 2**53) would be best.
But it doesn't
>>b = gmpy.mpq(a)
b
mpq(3,5)
Why do you suppose that is?

For the same reason that str() does. See below.
For that matter, why
does
>>str(a)
'0.6'
give me an EXACT representation?

It doesn't. It just rounds at a lower number of decimal places than is necessary
to faithfully represent the number. str() is intended to give friendly results,
not strictly correct ones. In this case it happens that float(str(0.6)) == 0.6,
but this is not guaranteed. For most numbers that a user or programmer might
enter, there will only be a relatively small amount of precision necessary, and
float(str(x)) == x will tend to hold. That's why it does this.
Didn't you just
say it couldn't be represented exactly?

Yup.
Which is correct,
>>str(a)
'0.6'
or
>>repr(a)
'0.59999999999999998'
?

The latter.
How does gmpy make the conversion from float to rational?

gmpy has a configurable transformation between floats and the internal
representation. I believe the default goes through str().
How do you do that? Is it configurable at run time or something that
has to be done when compiled?

But it is still wrong to say "0.6 is definitely not the same as 3/5".
One can say 0.6 doesn't have an exact float representation and that
inexact representation is not the same as 3/5. And I suppose one can
be surprised that when this inexact representation is coerced to a
rational the result is now exact.

Would that be a fairer way of putting it?
>
--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco
Oct 2 '07 #26

P: n/a
On Oct 2, 5:27 pm, "mensana...@aol.com" <mensana...@aol.comwrote:
But it is still wrong to say "0.6 is definitely not the same as 3/5".
Out of context, I'd certainly agree. But from the context, I assumed
it was clear that the 0.6 was a Python float. I probably should have
made this clearer. My statement should probably have been something
like: a literal 0.6 in Python code does not have the same mathematical
value as the rational (or real) number 3/5.

Richard

Oct 2 '07 #27

P: n/a
On Oct 2, 5:43 pm, richy...@gmail.com wrote:
On Oct 2, 5:27 pm, "mensana...@aol.com" <mensana...@aol.comwrote:
But it is still wrong to say "0.6 is definitely not the same as 3/5".

Out of context, I'd certainly agree. But from the context, I assumed
it was clear that the 0.6 was a Python float. I probably should have
made this clearer. My statement should probably have been something
like: a literal 0.6 in Python code does not have the same mathematical
value as the rational (or real) number 3/5.
Ok, so maybe I should have said: the literal 0.6 isn't what gets added
to mpq(1,3) to form the sum. What actually is added is the 0.6 coerced
to an mpq which is then added to mpq(1,3). So what 0.6 is as a float
is
relevent only to what it gets coerced to.
>
Richard

Oct 2 '07 #28

P: n/a
Neil Cerutti wrote:
>Another guess could be that real numbers being closed under the
four arithmetic operations, there is no danger to accidentally
step into complex numbers. OTOH floats and rationals are two
(conflicting) ways of extending integers.

You would have to adopt a few simple conversion rules, a la
Scheme. Inexact numbers are contagious, for example. It was
pretty shocking for a Scheme programmer to see the gmpy package
break that rule. ;)
There is another package that supports rationals.

http://pypi.python.org/pypi/clnum/1.2

One of the reasons I created this package is that I didn't like
implicit conversion of inexact numbers to exact numbers. Instead
clnum either raises an exception (with Python floats and complex)
or converts the rational to a compatible inexact type (with mpf
and cmpf).

Other reasons for creating this package are gmpy doesn't support
complex numbers or the functions in the math and cmath modules.

However, gmpy does have many capabilities that are not in clnum so
you need to choose based on the type of problem you want to solve.

Ray Buvel
Oct 3 '07 #29

P: n/a
On Mon, 01 Oct 2007 09:09:21 -0700, Arnaud Delobelle wrote:
As pointed out by others, implementations of rationals in Python abound.
Whereas there is a canonical representation of floats and ints (and even
longints) in the machine, it is not the case for rationals. Moreover
most programming tasks do not need rationals, so why burden the language
with them? If one needs them, there are perfectly adequate modules to
import (even though I, like many others I suspect, have my own
implementation in pure Python). Finally, arithmetic would become very
confusing if there were three distinct numeric types; it already causes
enough confusion with two!
Or, to put it another way:
As pointed out by others, implementations of sets in Python abound.
Whereas there is a canonical representation of floats and ints in the
machine, it is not the case for sets. Moreover most programming tasks do
not need sets, so why burden the language with them? If one needs them,
there are perfectly adequate modules to import (even though I, like many
others I suspect, have my own implementation in pure Python). Finally,
programming would become very confusing if there were three distinct
sequence types; it already causes enough confusion with two!

--
Steven.
Oct 4 '07 #30

P: n/a
Steven D'Aprano <st***@REMOVE-THIS-cybersource.com.auwrites:
implementation in pure Python). Finally, arithmetic would become very
confusing if there were three distinct numeric types; it already causes
enough confusion with two!
There's already ints, longs, floats, complexes, and decimals. What's
the problem with one more?
Oct 4 '07 #31

P: n/a
On Thu, 04 Oct 2007 02:47:27 -0700, Paul Rubin wrote:
Steven D'Aprano <st***@REMOVE-THIS-cybersource.com.auwrites:
implementation in pure Python). Finally, arithmetic would become
very confusing if there were three distinct numeric types; it already
causes enough confusion with two!

There's already ints, longs, floats, complexes, and decimals. What's
the problem with one more?
Having different data types for different needs isn't a bug, it's a
feature.

Besides, ints and longs are more or less the same data type now, or at
least they are in the process of being integrated.

--
Steven.
Oct 4 '07 #32

P: n/a
On Tue, 02 Oct 2007 06:07:15 +0000, Rhamphoryncus wrote:
On Sep 30, 7:35 pm, andresj <andres.j....@gmail.comwrote:
>I was doing some programming in Python, and the idea came to my mind:
using fractions instead of floats when doing 2/5.

The core problem with rationals (other than the inability to handle
irrationals)
If that's a problem, it is one shared by ints and floats.

is their tendency to require more and more memory as
calculations progress. This means they get mysteriously slower and
slower.

http://mail.python.org/pipermail/pyt...er/166630.html
I've read that thread, and although I see the claim made that rationals
are slow, I don't see the claim that they get "mysteriously" slower as
calculations progress. (And if they did, it would hardly be a mystery if
we know it is because they use more memory.)

I guess that could occur with unlimited precision rationals, in the same
way that it could occur with ever-larger longints, but I don't see how it
could occur with a simpler, limited precision implementation.

--
Steven.
Oct 4 '07 #33

This discussion thread is closed

Replies have been disabled for this discussion.