Maybe we could make a C implementation of the Fraction module? That would
be nice.
On Sun, May 31, 2015 at 8:28 PM, <python-ideas-request@python.org> wrote:
Send Python-ideas mailing list submissions to
python-ideas@python.org
To subscribe or unsubscribe via the World Wide Web, visit
https://mail.python.org/mailman/listinfo/python-ideas
or, via email, send a message with subject or body 'help' to
python-ideas-request@python.org
You can reach the person managing the list at
python-ideas-owner@python.org
When replying, please edit your Subject line so it is more specific
than "Re: Contents of Python-ideas digest..."
Today's Topics:
1. Re: Python Float Update (Chris Angelico)
2. Re: Python Float Update (random832@fastmail.us)
3. Re: Python Float Update (Jim Witschey)
4. Re: Python Float Update (David Mertz)
----------------------------------------------------------------------
Message: 1
Date: Mon, 1 Jun 2015 12:48:12 +1000
From: Chris Angelico <rosuav@gmail.com>
Cc: python-ideas <python-ideas@python.org>
Subject: Re: [Python-ideas] Python Float Update
Message-ID:
<CAPTjJmr=LurRUoKH3KVVYpMFc=
W5h6etG5TscV5uU6zWhxVbgQ@mail.gmail.com>
Content-Type: text/plain; charset=UTF-8
On Mon, Jun 1, 2015 at 12:25 PM, u8y7541 The Awesome Person
<surya.subbarao1@gmail.com> wrote:
I will be presenting a modification to the float class, which will
improve its speed and accuracy (reduce floating point errors). This is
applicable because Python uses a numerator and denominator rather than a
sign and mantissa to represent floats.
First, I propose that a float's integer ratio should be accurate. For
example, (1 / 3).as_integer_ratio() should return (1, 3). Instead, it
returns(6004799503160661, 18014398509481984).
I think you're misunderstanding the as_integer_ratio method. That
isn't how Python works internally; that's a service provided for
parsing out float internals into something more readable. What you
_actually_ are working with is IEEE 754 binary64. (Caveat: I have no
idea what Python-the-language stipulates, nor what other Python
implementations use, but that's what CPython uses, and you did your
initial experiments with CPython. None of this discussion applies *at
all* if a Python implementation doesn't use IEEE 754.) So internally,
1/3 is stored as:
0 <-- sign bit (positive)
01111111101 <-- exponent (1021)
0101010101010101010101010101010101010101010101010101 <-- mantissa (52
bits, repeating)
The exponent is offset by 1023, so this means 1.010101.... divided by
2?; the original repeating value is exactly equal to 4/3, so this is
correct, but as soon as it's squeezed into a finite-sized mantissa, it
gets rounded - in this case, rounded down.
That's where your result comes from. It's been rounded such that it
fits inside IEEE 754, and then converted back to a fraction
afterwards. You're never going to get an exact result for anything
with a denominator that isn't a power of two. Fortunately, Python does
offer a solution: store your number as a pair of integers, rather than
as a packed floating point value, and all calculations truly will be
exact (at the cost of performance):
one_third = fractions.Fraction(1, 3)
one_eighth = fractions.Fraction(1, 8)
one_third + one_eighth
Fraction(11, 24)
This is possibly more what you want to work with.
ChrisA
------------------------------
Message: 2
Date: Sun, 31 May 2015 23:14:06 -0400
From: random832@fastmail.us
To: python-ideas@python.org
Subject: Re: [Python-ideas] Python Float Update
Message-ID:
<1433128446.31560.283106753.6D60F98F@webmail.messagingengine.com>
Content-Type: text/plain
On Sun, May 31, 2015, at 22:25, u8y7541 The Awesome Person wrote:
First, I propose that a float's integer ratio should be accurate. For
example, (1 / 3).as_integer_ratio() should return (1, 3). Instead, it
returns(6004799503160661, 18014398509481984).
Even though he's mistaken about the core premise, I do think there's a
kernel of a good idea here - it would be nice to have a method (maybe
as_integer_ratio, maybe with some parameter added, maybe a different
method) to return with the smallest denominator that would result in
exactly the original float if divided out, rather than merely the
smallest power of two.
------------------------------
Message: 3
Date: Mon, 01 Jun 2015 03:21:36 +0000
From: Jim Witschey <jim.witschey@gmail.com>
To: Chris Angelico <rosuav@gmail.com>
Cc: python-ideas <python-ideas@python.org>
Subject: Re: [Python-ideas] Python Float Update
Message-ID:
<CAF+a8-q6kbOwcWk3F47+9PXf2vKgM9ao1uh5=qBw10jqzTC=
kg@mail.gmail.com>
Content-Type: text/plain; charset="utf-8"
Teachable moments about the implementation of floating-point aside,
something in this neighborhood has been considered and rejected before, in
PEP 240. However, that was in 2001 - it was apparently created the same day
as PEP 237, which introduced transparent conversion of machine ints to
bignums in the int type.
I think hiding hardware number implementations has been a success for
integers - it's a far superior API. It could be for rationals as well.
Has something like this thread's original proposal - interpeting
decimal-number literals as fractional values and using fractions as the
result of integer arithmetic - been seriously discussed more recently than
PEP 240? If so, why haven't they been implemented? Perhaps enough has
changed that it's worth reconsidering.
On Sun, May 31, 2015 at 22:49 Chris Angelico <rosuav@gmail.com> wrote:
On Mon, Jun 1, 2015 at 12:25 PM, u8y7541 The Awesome Person
<surya.subbarao1@gmail.com> wrote:
I will be presenting a modification to the float class, which will
improve its speed and accuracy (reduce floating point errors). This is
applicable because Python uses a numerator and denominator rather than a
sign and mantissa to represent floats.
First, I propose that a float's integer ratio should be accurate. For
example, (1 / 3).as_integer_ratio() should return (1, 3). Instead, it
returns(6004799503160661, 18014398509481984).
I think you're misunderstanding the as_integer_ratio method. That
isn't how Python works internally; that's a service provided for
parsing out float internals into something more readable. What you
_actually_ are working with is IEEE 754 binary64. (Caveat: I have no
idea what Python-the-language stipulates, nor what other Python
implementations use, but that's what CPython uses, and you did your
initial experiments with CPython. None of this discussion applies *at
all* if a Python implementation doesn't use IEEE 754.) So internally,
1/3 is stored as:
0 <-- sign bit (positive)
01111111101 <-- exponent (1021)
0101010101010101010101010101010101010101010101010101 <-- mantissa (52
bits, repeating)
The exponent is offset by 1023, so this means 1.010101.... divided by
2?; the original repeating value is exactly equal to 4/3, so this is
correct, but as soon as it's squeezed into a finite-sized mantissa, it
gets rounded - in this case, rounded down.
That's where your result comes from. It's been rounded such that it
fits inside IEEE 754, and then converted back to a fraction
afterwards. You're never going to get an exact result for anything
with a denominator that isn't a power of two. Fortunately, Python does
offer a solution: store your number as a pair of integers, rather than
as a packed floating point value, and all calculations truly will be
exact (at the cost of performance):
one_third = fractions.Fraction(1, 3)
one_eighth = fractions.Fraction(1, 8)
one_third + one_eighth
Fraction(11, 24)
This is possibly more what you want to work with.
ChrisA
_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/