Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #51557

Unexpected results comparing float to Fraction

Path csiph.com!newsfeed.hal-mli.net!feeder3.hal-mli.net!newsfeed.hal-mli.net!feeder1.hal-mli.net!newsfeed.xs4all.nl!newsfeed1.news.xs4all.nl!xs4all!newsgate.cistron.nl!newsgate.news.xs4all.nl!post.news.xs4all.nl!not-for-mail
Return-Path <oscar.j.benjamin@gmail.com>
X-Original-To python-list@python.org
Delivered-To python-list@mail.python.org
X-Spam-Status OK 0.039
X-Spam-Evidence '*H*': 0.92; '*S*': 0.00; 'syntax': 0.04; 'mrab': 0.05; 'float': 0.07; 'strict': 0.07; 'ugly': 0.07; 'highlighting': 0.09; 'python': 0.11; 'above?': 0.16; 'coercion': 0.16; 'coercions': 0.16; 'question)': 0.16; 'rounding': 0.16; 'unexpected': 0.16; 'wrote:': 0.18; 'all,': 0.19; 'bit': 0.19; 'module': 0.19; 'trying': 0.19; 'import': 0.22; 'preferred': 0.22; 'this?': 0.23; 'comparing': 0.24; 'fraction': 0.24; 'script': 0.25; 'header:In-Reply-To:1': 0.27; 'point': 0.28; 'message- id:@mail.gmail.com': 0.30; "i'm": 0.30; 'gives': 0.31; 'code': 0.31; 'apparently': 0.31; "d'aprano": 0.31; 'equality': 0.31; 'steven': 0.31; 'quite': 0.32; 'convert': 0.35; 'test': 0.35; 'but': 0.35; 'received:google.com': 0.35; 'there': 0.35; 'false': 0.36; 'scheme': 0.36; 'doing': 0.36; 'possible': 0.36; 'should': 0.36; 'expected': 0.38; 'represent': 0.38; 'to:addr:python-list': 0.38; 'expect': 0.39; 'does': 0.39; 'to:addr:python.org': 0.39; 'how': 0.40; 'problems.': 0.60; 'numbers': 0.61; "you're": 0.61; 'guarantee': 0.63; 'kind': 0.63; 'such': 0.63; 'july': 0.63; 'more': 0.64; 'situation': 0.65; 'results': 0.69; 'limit': 0.70; 'computation.': 0.84; 'float,': 0.84; 'oscar': 0.84; 'careful': 0.91; 'do:': 0.91; 'subject:results': 0.91; 'refuse': 0.93; '2013': 0.98
DKIM-Signature v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :content-type; bh=mbDPVgxWN7aDQ3EGZ1O36ReWpE0RlJtD+Jr78Maw7TU=; b=mDmYMXqA0lkNbSlhgVbaFkYJ8Ggt3wsJJhSq5raCDnuYdQidpD8UYuDj0QiDgKyLF1 EpifXolOOL1nTvvH1gRHIZPLS3LBIm+Bl8N+XOMoS8vtDjIU476qdgSevQ4G4IDzipze Er8sMYNYtGxCY0yUtJHO1527dVg6Vx7q2FEE8JU0S1sKZENeDQN4qg22d7xLRJU7+xx5 ohTElVt4qYbHSUozJfYsV/V+8UXTU8nVCxhAV/jO5pv0c0KkD0FKdTzkh/Z6zc19b9zH mS2h2kBTaS0b90Ej1qGgiWpLoVyDc5/29agp1Y6eSl8/5du9tS9XbRypgMMn0M3vjaPb M/Ug==
X-Received by 10.52.183.199 with SMTP id eo7mr16796461vdc.24.1375191144611; Tue, 30 Jul 2013 06:32:24 -0700 (PDT)
MIME-Version 1.0
In-Reply-To <51F693B4.9000201@mrabarnett.plus.com>
References <51f68d9c$0$30000$c3e8da3$5496439d@news.astraweb.com> <51F693B4.9000201@mrabarnett.plus.com>
From Oscar Benjamin <oscar.j.benjamin@gmail.com>
Date Tue, 30 Jul 2013 14:32:04 +0100
Subject Unexpected results comparing float to Fraction
To python-list@python.org
Content-Type text/plain; charset=ISO-8859-1
X-BeenThere python-list@python.org
X-Mailman-Version 2.1.15
Precedence list
List-Id General discussion list for the Python programming language <python-list.python.org>
List-Unsubscribe <http://mail.python.org/mailman/options/python-list>, <mailto:python-list-request@python.org?subject=unsubscribe>
List-Archive <http://mail.python.org/pipermail/python-list/>
List-Post <mailto:python-list@python.org>
List-Help <mailto:python-list-request@python.org?subject=help>
List-Subscribe <http://mail.python.org/mailman/listinfo/python-list>, <mailto:python-list-request@python.org?subject=subscribe>
Newsgroups comp.lang.python
Message-ID <mailman.5307.1375191153.3114.python-list@python.org> (permalink)
Lines 74
NNTP-Posting-Host 2001:888:2000:d::a6
X-Trace 1375191153 news.xs4all.nl 16012 [2001:888:2000:d::a6]:60365
X-Complaints-To abuse@xs4all.nl
Xref csiph.com comp.lang.python:51557

Show key headers only | View raw


On 29 July 2013 17:09, MRAB <python@mrabarnett.plus.com> wrote:
> On 29/07/2013 16:43, Steven D'Aprano wrote:
>>
>> Comparing floats to Fractions gives unexpected results:

You may not have expected these results but as someone who regularly
uses the fractions module I do expect them.

>> # Python 3.3
>> py> from fractions import Fraction
>> py> 1/3 == Fraction(1, 3)
>> False
>>
>> but:
>>
>> py> 1/3 == float(Fraction(1, 3))
>> True

Why would you do the above? You're deliberately trying to create a
float with a value that you know is not representable by the float
type. The purpose of Fractions is precisely that they can represent
all rational values, hence avoiding these problems.

When I use Fractions my intention is to perform exact computation. I
am very careful to avoid allowing floating point imprecision to sneak
into my calculations. Mixing floats and fractions in computation is
not IMO a good use of duck-typing.

>> I expected that float-to-Fraction comparisons would convert the Fraction
>> to a float, but apparently they do the opposite: they convert the float
>> to a Fraction:
>>
>> py> Fraction(1/3)
>> Fraction(6004799503160661, 18014398509481984)
>>
>> Am I the only one who is surprised by this? Is there a general rule for
>> which way numeric coercions should go when doing such comparisons?

I would say that if type A is a strict superset of type B then the
coercion should be to type A. This is the case for float and Fraction
since any float can be represented exactly as a Fraction but the
converse is not true.

> I'm surprised that Fraction(1/3) != Fraction(1, 3); after all, floats
> are approximate anyway, and the float value 1/3 is more likely to be
> Fraction(1, 3) than Fraction(6004799503160661, 18014398509481984).

Refuse the temptation to guess: Fraction(float) should give the exact
value of the float. It should not give one of the countably infinite
number of other possible rational numbers that would (under a
particular rounding scheme and the floating point format in question)
round to the same float. If that is the kind of equality you would
like to test for in some particular situation then you can do so by
coercing to float explicitly.

Calling Fraction(1/3) is a misunderstanding of what the fractions
module is for and how to use it. The point is to guarantee avoiding
floating point errors; this is impossible if you use floating point
computations to initialise Fractions.

Writing Fraction(1, 3) does look a bit ugly so my preferred way to
reduce the boiler-plate in a script that uses lots of Fraction
"literals" is to do:

from fractions import Fraction as F

# 1/3 + 1/9 + 1/27 + ...
limit = F('1/3') / (1 - F('1/3'))

That's not as good as dedicated syntax but with code highlighting it's
still quite readable.


Oscar

Back to comp.lang.python | Previous | NextPrevious in thread | Next in thread | Find similar | Unroll thread


Thread

Unexpected results comparing float to Fraction Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-07-29 15:43 +0000
  Re: Unexpected results comparing float to Fraction Ian Kelly <ian.g.kelly@gmail.com> - 2013-07-29 09:50 -0600
  Re: Unexpected results comparing float to Fraction MRAB <python@mrabarnett.plus.com> - 2013-07-29 17:09 +0100
  Re: Unexpected results comparing float to Fraction Chris Angelico <rosuav@gmail.com> - 2013-07-29 17:20 +0100
    Re: Unexpected results comparing float to Fraction Rotwang <sg552@hotmail.co.uk> - 2013-07-29 19:20 +0100
    Re: Unexpected results comparing float to Fraction Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-07-29 19:32 +0000
  Re: Unexpected results comparing float to Fraction MRAB <python@mrabarnett.plus.com> - 2013-07-29 17:48 +0100
    Re: Unexpected results comparing float to Fraction Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-07-29 17:27 +0000
  Re: Unexpected results comparing float to Fraction Ian Kelly <ian.g.kelly@gmail.com> - 2013-07-29 10:40 -0600
    Re: Unexpected results comparing float to Fraction Rotwang <sg552@hotmail.co.uk> - 2013-07-29 19:16 +0100
      Re: Unexpected results comparing float to Fraction Ian Kelly <ian.g.kelly@gmail.com> - 2013-07-29 13:33 -0600
  Re: Unexpected results comparing float to Fraction MRAB <python@mrabarnett.plus.com> - 2013-07-29 18:04 +0100
    Re: Unexpected results comparing float to Fraction Grant Edwards <invalid@invalid.invalid> - 2013-07-29 18:46 +0000
    Re: Unexpected results comparing float to Fraction Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-07-29 20:19 +0000
  Re: Unexpected results comparing float to Fraction Terry Reedy <tjreedy@udel.edu> - 2013-07-29 13:08 -0400
    Re: Unexpected results comparing float to Fraction Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-07-29 17:29 +0000
      Re: Unexpected results comparing float to Fraction Terry Reedy <tjreedy@udel.edu> - 2013-07-29 16:48 -0400
  Re: Unexpected results comparing float to Fraction Chris Angelico <rosuav@gmail.com> - 2013-07-29 18:14 +0100
  Re: Unexpected results comparing float to Fraction Ian Kelly <ian.g.kelly@gmail.com> - 2013-07-29 11:35 -0600
  Re: Unexpected results comparing float to Fraction Serhiy Storchaka <storchaka@gmail.com> - 2013-07-29 22:34 +0300
  Re: Unexpected results comparing float to Fraction Ian Kelly <ian.g.kelly@gmail.com> - 2013-07-29 14:35 -0600
  Unexpected results comparing float to Fraction Oscar Benjamin <oscar.j.benjamin@gmail.com> - 2013-07-30 14:32 +0100
  Re: Unexpected results comparing float to Fraction Tony the Tiger <tony@tiger.invalid> - 2013-07-31 15:23 -0500
    Re: Unexpected results comparing float to Fraction Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-08-01 06:20 +0000
      Re: Unexpected results comparing float to Fraction Chris Angelico <rosuav@gmail.com> - 2013-08-01 07:32 +0100
      Re: Unexpected results comparing float to Fraction Oscar Benjamin <oscar.j.benjamin@gmail.com> - 2013-08-01 10:44 +0100
      Re: Unexpected results comparing float to Fraction Chris Angelico <rosuav@gmail.com> - 2013-08-01 10:48 +0100

csiph-web