Re: Comparing float and decimal

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Terry Reedy

    Re: Comparing float and decimal

    Gerhard Häring wrote:
    D'Arcy J.M. Cain wrote:
    >I'm not sure I follow this logic. Can someone explain why float and
    >integer can be compared with each other and decimal can be compared to
    >integer but decimal can't be compared to float?
    >>
    >>>>from decimal import Decimal
    >>>>i = 10
    >>>>f = 10.0
    >>>>d = Decimal("10.00" )
    >>>>i == f
    >True
    >>>>i == d
    >True
    >>>>f == d
    >False
    >
    I can give you the technical answer after reading the sources of the
    decimal module: you can only compare to Decimal what can be converted to
    Decimal. And that is int, long and another Decimal.
    The new fractions module acts differently, which is to say, as most
    would want.
    >>from fractions import Fraction as F
    >>F(1) == 1.0
    True
    >>F(1.0)
    Traceback (most recent call last):
    File "<pyshell#2 0>", line 1, in <module>
    F(1.0)
    File "C:\Program Files\Python30\ lib\fractions.p y", line 97, in __new__
    numerator = operator.index( numerator)
    TypeError: 'float' object cannot be interpreted as an integer
    >>F(1,2) == .5
    True
    >>.5 == F(1,2)
    True

    so Fraction obviously does comparisons differently.

    Decimal is something of an anomaly in Python because it was written to
    exactly follow an external standard, with no concessions to what would
    be sensible for Python. It is possible that that standard mandates that
    Decimals not compare to floats.

    tjr

  • Nick Craig-Wood

    #2
    Re: Comparing float and decimal

    Terry Reedy <tjreedy@udel.e duwrote:
    The new fractions module acts differently, which is to say, as most
    would want.
    >
    >>from fractions import Fraction as F
    >>F(1) == 1.0
    True
    >>F(1.0)
    Traceback (most recent call last):
    File "<pyshell#2 0>", line 1, in <module>
    F(1.0)
    File "C:\Program Files\Python30\ lib\fractions.p y", line 97, in __new__
    numerator = operator.index( numerator)
    TypeError: 'float' object cannot be interpreted as an integer
    Both the Fraction module and the Decimal module could represent floats
    exactly and reversibly since floats are of the form

    mantissa * 2**exponent

    which is exactly representable as a fraction (rational) and also as

    mantissa2 * 10**exponent2

    as to why we don't do this...

    I guess it is to preserve the sanity of the user when they write
    fraction(0.1) or decimal(0.1) did they really mean fraction(1,10),
    decimal("0.1") or the exact representations which are
    decimal("0.1000 000000000000055 511151231257827 021181583404541 015625")
    and fraction(360287 9701896397,2**5 5)

    Given that we let the exact representations leak out anyway (which
    causes a lot of FAQs in this list), eg
    >>0.1
    0.1000000000000 0001

    IMHO We should put the exact conversions in for floats to Decimal and
    Fraction by default and add a new section to the FAQ!

    In that way people will see floats for what they really are - a crude
    approximation to a rational number ;-)

    --
    Nick Craig-Wood <nick@craig-wood.com-- http://www.craig-wood.com/nick

    Comment

    • Mark Dickinson

      #3
      Re: Comparing float and decimal

      On Sep 23, 7:31 pm, Terry Reedy <tjre...@udel.e duwrote:
      Decimal is something of an anomaly in Python because it was written to
      exactly follow an external standard, with no concessions to what would
      be sensible for Python.  It is possible that that standard mandates that
      Decimals not compare to floats.
      I don't think the standard says anything about interactions between
      Decimals and floats. But there's certainly been a feeling amongst at
      least some of the developers that the job of Python's decimal module
      is
      to implement the standard and no more, and that extensions to its
      functionality belong elsewhere.

      Regarding equality, there's at least one technical issue: the
      requirement
      that objects that compare equal hash equal. How do you come up with
      efficient hash operations for integers, floats, Decimals and Fractions
      that satisfy this requirement?

      For other arithmetic operations: should the sum of a float and a
      Decimal
      produce a Decimal or a float? Why? It's not at all clear to me that
      either of these types is 'higher up' the numerical tower than the
      other.

      Mark

      Comment

      • Terry Reedy

        #4
        Re: Comparing float and decimal

        Mark Dickinson wrote:
        On Sep 23, 7:31 pm, Terry Reedy <tjre...@udel.e duwrote:
        >Decimal is something of an anomaly in Python because it was written to
        >exactly follow an external standard, with no concessions to what would
        >be sensible for Python. It is possible that that standard mandates that
        >Decimals not compare to floats.
        >
        I don't think the standard says anything about interactions between
        Decimals and floats.
        If there is not now, there could be in the future, and the decimal
        authors are committed to follow the standard wherever it goes.
        Therefore, the safe course, to avoid possible future deprecations due to
        doing too much, is to only do what is mandated.
        But there's certainly been a feeling amongst at
        least some of the developers that the job of Python's decimal module
        is to implement the standard and no more, and that extensions to its
        functionality belong elsewhere.
        For the reason just stated. A slightly different take is this. The
        reason for following the standard is so that decimal code in Python is
        exact interconversion both from and to decimal code in other languages.
        (And one reason for *that* is that one purpose of the standard is to
        reliably implement legal and contractual standards for financial
        calculations.) Using extensions in Python could break/deprecate code
        translated away from Python.
        Regarding equality, there's at least one technical issue: the
        requirement
        that objects that compare equal hash equal. How do you come up with
        efficient hash operations for integers, floats, Decimals and Fractions
        that satisfy this requirement?
        For integral values, this is no problem.
        >>hash(1) == hash(1.0) == hash(decimal.De cimal(1)) ==
        hash(fractions. Fraction(1)) == 1
        True
        For other arithmetic operations: should the sum of a float and a
        Decimal produce a Decimal or a float? Why? It's not at all clear to me that
        either of these types is 'higher up' the numerical tower than the
        other.
        Floats and fractions have the same issue. Fractions are converted to
        floats. I can think of two reasons: float operations are faster; floats
        are my typically thought of as inexact and since the result is likely to
        be inexact (rounded), float is the more appropriate type to express
        that. Anyone who disagrees with the choice for their application can
        explicitly convert the float to a fraction.

        Decimals can also be converted to floats (they also have a __float__
        method). But unlike fractions, the conversion must be explicit, using
        float(decimal), instead of implicit, as with ints and fractions.

        Someone *could* write a PyDecimal wrapper that would do implicit
        conversion and thereby more completely integrate decimals with other
        Python numbers, but I doubt that saving transitivity of equality will be
        sufficient motivation ;-).

        Terry Jan Reedy

        Comment

        • Steven D'Aprano

          #5
          Re: Comparing float and decimal

          On Wed, 24 Sep 2008 04:30:03 -0500, Nick Craig-Wood wrote:

          Both the Fraction module and the Decimal module could represent floats
          exactly and reversibly since floats are of the form
          >
          mantissa * 2**exponent
          >
          which is exactly representable as a fraction (rational) and also as
          >
          mantissa2 * 10**exponent2
          >
          as to why we don't do this...
          >
          I guess it is to preserve the sanity of the user when they write
          fraction(0.1) or decimal(0.1) did they really mean fraction(1,10),
          decimal("0.1") or the exact representations which are
          decimal("0.1000 000000000000055 511151231257827 021181583404541 015625") and
          fraction(360287 9701896397,2**5 5)

          I would say that in practice the chances that somebody *actually* wanted
          0.1000000000000 000055511151231 257827021181583 404541015625 when they wrote
          0.1 is about the same as the chances that the BDFL will support braces in
          Python 3.0.

          (Hint: "from __future__ import braces")

          Given that we let the exact representations leak out anyway (which
          causes a lot of FAQs in this list), eg
          >
          >>>0.1
          0.1000000000000 0001
          >
          IMHO We should put the exact conversions in for floats to Decimal and
          Fraction by default and add a new section to the FAQ!

          But of the reasons for having the Decimal module is to avoid such leaky
          abstractions. Without Decimal (or fraction) there's no obvious way to get
          0.1 exactly. It seems perverse to suggest that by default Decimal should
          deliberately expose the same leaky abstraction that causes so much
          trouble when people use floats.
          In that way people will see floats for what they really are - a crude
          approximation to a rational number ;-)
          You can already see that just by printing a float:
          >>0.3
          0.2999999999999 9999
          >>0.1
          0.1000000000000 0001


          --
          Steven

          Comment

          • Mark Dickinson

            #6
            Re: Comparing float and decimal

            On Sep 24, 6:18 pm, Terry Reedy <tjre...@udel.e duwrote:
            If there is not now, there could be in the future, and the decimal
            authors are committed to follow the standard wherever it goes.
            Therefore, the safe course, to avoid possible future deprecations due to
            doing too much, is to only do what is mandated.
            Makes sense. It looks as though the standard's pretty stable now
            though; I'd be quite surprised to see it evolve to include discussion
            of floats. But then again, people thought it was stable just before
            all the extra transcendental operations appeared. :-)
            For integral values, this is no problem.
             >>hash(1) == hash(1.0) == hash(decimal.De cimal(1)) ==
            hash(fractions. Fraction(1)) == 1
            True
            Getting integers and Decimals to hash equal was actually
            something of a pain, and required changing the way that
            the hash of a long was computed. The problem in a nutshell:
            what's the hash of Decimal('1e1000 00000')? The number is
            clearly an integer, so its hash should be the same as that
            of 10**100000000. But computing 10**100000000, and then
            finding its hash, is terribly slow... (Try
            hash(Decimal('1 e100000000')) in Python 2.5 and see
            what happens! It's fixed in Python 2.6.)

            As more numeric types get added to Python, this
            'equal implies equal hash' requirement becomes more
            and more untenable, and difficult to maintain. I also find
            it a rather unnatural requirement: numeric equality
            is, to me, a weaker equivalence relation than the one
            that should be used for identifying keys in dictionaries,
            elements of sets, etc. Fraction(1, 2) and 0.5 should, to my
            eyes, be considered
            different elements of a set. But the only way to 'fix' this
            would be to have Python recognise two different types of
            equality, and then it wouldn't be Python any more.

            The SAGE folks also discovered that they couldn't
            maintain the hash requirement.
            Decimals can also be converted to floats (they also have a  __float__
            method).  But unlike fractions, the conversion must be explicit, using
            float(decimal), instead of implicit, as with ints and fractions.
            Maybe: if I *had* to pick a direction, I'd make float + Decimal
            produce a Decimal, on the basis that Decimal is arbitrary precision
            and that the float->Decimal conversion can be made losslessly.
            But then there are a whole host of decisions one has to make
            about rounding, significant zeros, ... (And then, as you point
            out, Cowlishaw might come out with a new version of the standard
            that does include interactions with floats, and makes an entirely
            different set of decisions...)

            Mark

            Comment

            • Terry Reedy

              #7
              Re: Comparing float and decimal

              Mark Dickinson wrote:
              On Sep 24, 6:18 pm, Terry Reedy <tjre...@udel.e duwrote:
              >If there is not now, there could be in the future, and the decimal
              >authors are committed to follow the standard wherever it goes.
              >Therefore, the safe course, to avoid possible future deprecations due to
              >doing too much, is to only do what is mandated.
              >
              Makes sense. It looks as though the standard's pretty stable now
              though; I'd be quite surprised to see it evolve to include discussion
              of floats. But then again, people thought it was stable just before
              all the extra transcendental operations appeared. :-)
              What got me were the bizarre new 'logical' operations whose addition
              were rather nonsensical from a Python viewpoint (though probably
              sensible from an IBM profit business viewpoint). With those added, and
              with this thread, I have decided that Decimals best be thought of as a
              separate universe, not to be mixed with other numbers unless one has
              good reason to and understands the possible anomalies of doing so. For
              pure finance apps, I would think that there should be little reason to mix.

              tjr

              Comment

              Working...