Using fractions instead of floats

Discussion in 'Python' started by andresj, Oct 1, 2007.

  1. andresj

    andresj Guest

    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.
    andresj, Oct 1, 2007
    #1
    1. Advertising

  2. andresj

    Ben Finney Guest

    andresj <> writes:

    > 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
    Ben Finney, Oct 1, 2007
    #2
    1. Advertising

  3. andresj

    andresj Guest

    On Sep 30, 6:48 pm, Ben Finney <>
    wrote:
    > andresj <> writes:
    > > 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.)
    andresj, Oct 1, 2007
    #3
  4. andresj

    Guest

    On Sep 30, 8:35?pm, andresj <> wrote:
    > 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, 2007
    #4
  5. On Sep 30, 9:35 pm, andresj <> wrote:
    > 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
    George Sakkis, Oct 1, 2007
    #5
  6. Fwd: Using fractions instead of floats

    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 <> wrote:
    > On Sep 30, 9:35 pm, andresj <> wrote:
    > > 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/
    Andres Riofrio, Oct 1, 2007
    #6
  7. En Sun, 30 Sep 2007 23:36:23 -0300, George Sakkis
    <> escribi�:

    > On Sep 30, 9:35 pm, andresj <> wrote:
    >> 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
    Gabriel Genellina, Oct 1, 2007
    #7
  8. andresj

    Terry Reedy Guest

    "Andres Riofrio" <> wrote in message
    news:...
    | 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
    Terry Reedy, Oct 1, 2007
    #8
  9. Re: Fwd: Using fractions instead of floats

    En Mon, 01 Oct 2007 00:10:05 -0300, Andres Riofrio
    <> escribi�:

    > 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
    Gabriel Genellina, Oct 1, 2007
    #9
  10. Re: Fwd: Using fractions instead of floats

    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
    Laurent Pointal, Oct 1, 2007
    #10
  11. Gabriel Genellina <> wrote:
    > 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 <> -- http://www.craig-wood.com/nick
    Nick Craig-Wood, Oct 1, 2007
    #11
  12. andresj

    Stargaming Guest

    Re: Fwd: Using fractions instead of floats

    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
    Stargaming, Oct 1, 2007
    #12
  13. On Oct 1, 2:35 am, andresj <> wrote:

    [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
    Arnaud Delobelle, Oct 1, 2007
    #13
  14. andresj

    Neil Cerutti Guest

    On 2007-10-01, Arnaud Delobelle <> wrote:
    > 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
    Neil Cerutti, Oct 1, 2007
    #14
  15. On Oct 1, 6:26 pm, Neil Cerutti <> wrote:
    > On 2007-10-01, Arnaud Delobelle <> wrote:
    >
    > > 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
    Arnaud Delobelle, Oct 1, 2007
    #15
  16. andresj

    andresj Guest


    > > On 2007-10-01, Arnaud Delobelle <> wrote:

    >
    > > > Finally, arithmetic would become very confusing if there were
    > > > three distinct numeric types; it already causes enough
    > > > confusion with two!


    Well, yeah... I get what you are saying, that would be confusing...

    Terry Reedy and Laurent Pointal:
    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.

    Gabriel Genellina, thanks for the suggestion of wrapping my code. I
    think it could be one way... But I think it would be too much trouble,
    I'll just go with writing fractions/rationals explicitly.

    And thanks to mensanator and Gabriel for the suggestion of gmpy, and
    to Nick for the example (It really helps to have an example, because
    it usually takes me hours to get to what I want in the
    documentations :). I think I will use that, when i get it working in
    Ubuntu. Do you guys know of any pre-made package or guides for getting
    it working in Ubuntu?

    Well, I guess my idea was not as good as I thought it was :). But
    anyways... I look forward to Python 3.0 (Specially the
    __future__.with_statement and the standardization of names-- cStringIO
    is just too ugly for my eyes!)
    andresj, Oct 2, 2007
    #16
  17. andresj

    Guest

    On Oct 1, 8:30 am, Nick Craig-Wood <> wrote:
    > >>> 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, 2007
    #17
  18. andresj

    Guest

    On Oct 1, 7:09 pm, andresj <> wrote:
    > > > On 2007-10-01, Arnaud Delobelle <> wrote:

    >
    > > > > Finally, arithmetic would become very confusing if there were
    > > > > three distinct numeric types; it already causes enough
    > > > > confusion with two!

    >
    > Well, yeah... I get what you are saying, that would be confusing...
    >
    > Terry Reedy and Laurent Pointal:
    > 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.
    >
    > Gabriel Genellina, thanks for the suggestion of wrapping my code. I
    > think it could be one way... But I think it would be too much trouble,
    > I'll just go with writing fractions/rationals explicitly.
    >
    > And thanks to mensanator and Gabriel for the suggestion of gmpy, and
    > to Nick for the example (It really helps to have an example,


    Would you like to see a more thorough example?

    First, go check out the Wikipedia article:
    <http://en.wikipedia.org/wiki/Collatz_conjecture>

    And scroll down the the section "Iterating on rational numbers
    with odd denominators". I added the section beginning with
    "The complete cycle being:..." through "And this is because...".

    Here's the Python program I used to develop that section.

    import gmpy

    def calc_pv_xyz(pv):
    """calculate Hailstone Function Parameters
    using Parity Vector instead of Sequence Vector
    (defined using (3n+1)/2)

    calc_pv_xyz(pv)
    pv: parity vector
    returns HailstoneFunctionParameters (x,y,z)
    """
    ONE = gmpy.mpz(1)
    TWO = gmpy.mpz(2)
    TWE = gmpy.mpz(3)
    twee = gmpy.mpz(sum(pv))
    twoo = gmpy.mpz(len(pv))
    x = TWO**twoo
    y = TWE**twee
    z = gmpy.mpz(0)
    c = gmpy.mpz(sum(pv)-1)
    for i,j in enumerate(pv):
    if j:
    z += TWE**c * TWO**i
    c -= ONE
    return (x,y,z)

    def iterating_on_rational(n): # Collatz for rational numbers
    # is numerator odd?
    if n.numer() % 2 == 1:
    n = (n*3 + 1)/2
    else:
    n = n/2
    print n,
    return n

    pv = [1,0,1,1,0,0,1]

    for i in xrange(len(pv)+1):
    print pv
    # get Hailstone Function parameters X,Y,Z
    xyz = calc_pv_xyz(pv)
    # calculate the Crossover Point Z/(X-Y)
    cp = gmpy.mpq(xyz[2],xyz[0]-xyz[1]) # as a rational number
    # start of loop cycle
    print cp,
    # start the cycle...
    n = iterating_on_rational(cp)
    # ...which MUST return to the starting point
    # since ALL rationals are valid Crossover Points
    # not just integers
    while n != cp:
    n = iterating_on_rational(n)
    print
    print
    # step through the cyclic permutations
    p = pv.pop(0)
    pv.append(p)

    ## parity vector cyclic permutations
    ##
    ## [1, 0, 1, 1, 0, 0, 1]
    ## 151/47 250/47 125/47 211/47 340/47 170/47 85/47 151/47
    ##
    ## [0, 1, 1, 0, 0, 1, 1]
    ## 250/47 125/47 211/47 340/47 170/47 85/47 151/47 250/47
    ##
    ## [1, 1, 0, 0, 1, 1, 0]
    ## 125/47 211/47 340/47 170/47 85/47 151/47 250/47 125/47
    ##
    ## [1, 0, 0, 1, 1, 0, 1]
    ## 211/47 340/47 170/47 85/47 151/47 250/47 125/47 211/47
    ##
    ## [0, 0, 1, 1, 0, 1, 1]
    ## 340/47 170/47 85/47 151/47 250/47 125/47 211/47 340/47
    ##
    ## [0, 1, 1, 0, 1, 1, 0]
    ## 170/47 85/47 151/47 250/47 125/47 211/47 340/47 170/47
    ##
    ## [1, 1, 0, 1, 1, 0, 0]
    ## 85/47 151/47 250/47 125/47 211/47 340/47 170/47 85/47
    ##
    ## [1, 0, 1, 1, 0, 0, 1]
    ## 151/47 250/47 125/47 211/47 340/47 170/47 85/47 151/47

    > because
    > it usually takes me hours to get to what I want in the
    > documentations :). I think I will use that, when i get it working in
    > Ubuntu. Do you guys know of any pre-made package or guides for getting
    > it working in Ubuntu?
    >
    > Well, I guess my idea was not as good as I thought it was :). But
    > anyways... I look forward to Python 3.0 (Specially the
    > __future__.with_statement and the standardization of names-- cStringIO
    > is just too ugly for my eyes!)
    , Oct 2, 2007
    #18
  19. andresj

    Guest

    On Oct 1, 7:20 pm, wrote:
    > On Oct 1, 8:30 am, Nick Craig-Wood <> wrote:
    >
    > > >>> 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, 2007
    #19
  20. andresj

    Guest

    On Oct 1, 9:03 pm, "" <> wrote:
    > On Oct 1, 7:20 pm, wrote:
    >
    > > On Oct 1, 8:30 am, Nick Craig-Wood <> wrote:

    >
    > > > >>> 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, 2007
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Eoin Mcloughlin

    Decimal places and huge fractions.

    Eoin Mcloughlin, Feb 11, 2004, in forum: Perl
    Replies:
    5
    Views:
    1,613
    Eoin Mcloughlin
    Feb 13, 2004
  2. Lee Jackson

    XSL-FO...Fractions?

    Lee Jackson, Dec 17, 2004, in forum: XML
    Replies:
    3
    Views:
    692
    David Carlisle
    Dec 17, 2004
  3. karp

    Adding two fractions

    karp, Nov 22, 2003, in forum: C++
    Replies:
    2
    Views:
    5,245
    Gary Labowitz
    Nov 22, 2003
  4. =?ISO-8859-1?Q?Mickel_Gr=F6nroos?=

    How do I get the fractions of the visible part of a canvas?

    =?ISO-8859-1?Q?Mickel_Gr=F6nroos?=, Jul 2, 2003, in forum: Python
    Replies:
    1
    Views:
    313
    Eric Brunel
    Jul 2, 2003
  5. Kosio

    Floats to chars and chars to floats

    Kosio, Sep 16, 2005, in forum: C Programming
    Replies:
    44
    Views:
    1,285
    Tim Rentsch
    Sep 23, 2005
Loading...

Share This Page