Interesting list Validity (True/False)

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Gabriel Genellina

    #31
    Re: Interesting list Validity (True/False)

    En Tue, 15 May 2007 01:37:07 -0300, mensanator@aol. com
    <mensanator@aol .comescribió:
    <quote emphasis added>
    Sec 2.2.3:
    Objects of different types, *--->except<---* different numeric types
    and different string types, never compare equal;
    </quote>
    >>
    >The exceptions you mean are not exceptions to "'X==Y' means 'X equals
    >Y'".
    >
    I never said they were. I said they were exceptions to
    "Obbjects of different types never compare equal".
    This is an unfortunate wording, and perhaps should read: "For most builtin
    types, objects of different types never compare equal; such objects are
    ordered consistently but arbitrarily (so that sorting a heterogeneous
    sequence yields a consistent result). The exceptions being different
    numeric types and different string types, that have a special treatment;
    see section 5.9 in the Reference Manual for details."

    And said section 5.9 should be updated too: "The objects need not have the
    same type. If both are numbers or strings, they are converted to a common
    type. Otherwise, objects of different builtin types always compare
    unequal, and are ordered consistently but arbitrarily. You can control
    comparison behavior of objects of non-builtin types by defining a __cmp__
    method or rich comparison methods like __gt__, described in section 3.4."

    I hope this helps a bit. Your performance issues don't have to do with the
    *definition* of equal or not equal, only with how someone decided to write
    the mpz class.

    --
    Gabriel Genellina

    Comment

    • mensanator@aol.com

      #32
      Re: Interesting list Validity (True/False)

      On May 15, 12:30 am, "Gabriel Genellina" <gagsl-...@yahoo.com.a r>
      wrote:
      En Tue, 15 May 2007 01:37:07 -0300, mensana...@aol. com
      <mensana...@aol .comescribió:
      >
      <quote emphasis added>
      Sec 2.2.3:
      Objects of different types, *--->except<---* different numeric types
      and different string types, never compare equal;
      </quote>
      >
      The exceptions you mean are not exceptions to "'X==Y' means 'X equals
      Y'".
      >
      I never said they were. I said they were exceptions to
      "Obbjects of different types never compare equal".
      >
      This is an unfortunate wording, and perhaps should read: "For most builtin
      types, objects of different types never compare equal; such objects are
      ordered consistently but arbitrarily (so that sorting a heterogeneous
      sequence yields a consistent result). The exceptions being different
      numeric types and different string types, that have a special treatment;
      see section 5.9 in the Reference Manual for details."
      >
      And said section 5.9 should be updated too: "The objects need not have the
      same type. If both are numbers or strings, they are converted to a common
      type.
      Except when they aren't.
      >>import gmpy
      >>a = 2**177149-1
      >>b = gmpy.mpz(2**177 149-1)
      >>a==b
      True
      >>print '%d' % (b)
      Traceback (most recent call last):
      File "<pyshell#4 >", line 1, in <module>
      print '%d' % (b)
      TypeError: int argument required

      So although the comparison operator is smart enough to realize
      the equivalency of numeric types and do the type conversion,
      the print statement isn't so smart.
      Otherwise, objects of different builtin types always compare
      unequal, and are ordered consistently but arbitrarily. You can control
      comparison behavior of objects of non-builtin types by defining a __cmp__
      method or rich comparison methods like __gt__, described in section 3.4."
      >
      I hope this helps a bit. Your performance issues don't have to do with the
      *definition* of equal or not equal,
      I didn't say that, I said the performance issues were related
      to type conversion. Can you explain how the "definition " of
      equal does not involve type conversion?
      only with how someone decided to write the mpz class.
      I'm beginning to think there's a problem there.
      >
      --
      Gabriel Genellina

      Comment

      • Gabriel Genellina

        #33
        Re: Interesting list Validity (True/False)

        En Tue, 15 May 2007 14:01:20 -0300, mensanator@aol. com
        <mensanator@aol .comescribió:
        On May 15, 12:30 am, "Gabriel Genellina" <gagsl-...@yahoo.com.a r>
        wrote:
        >And said section 5.9 should be updated too: "The objects need not have
        >the
        >same type. If both are numbers or strings, they are converted to a
        >common
        >type.
        >
        Except when they aren't.
        I think you don't get the difference between a builtin object, fully under
        the Python developers' control, and a user defined class that can behave
        arbitrarily at wish of its writer and for which the Python documentation
        barely can say a word.
        The docs say how will the Python interpreter try to compare objects
        (invoke the rich comparison methods, invoke __cmp__, etc) and how the
        *builtin* objects behave. For other objects, it's up to the object
        *writer* to provide such methods, and he can do whatever he wishes:

        pyclass Reversed(int):
        .... def __lt__(self, other): return cmp(int(self),o ther)>0
        .... def __gt__(self, other): return cmp(int(self),o ther)<0
        .... def __le__(self, other): return cmp(int(self),o ther)>=0
        .... def __ge__(self, other): return cmp(int(self),o ther)<=0
        ....
        py>
        pyj=Reversed(6)
        pyj==6
        True
        pyj>5
        False
        pyj>10
        True
        pyj<=5
        True

        You can't blame Python for this.
        >>>import gmpy
        >>>a = 2**177149-1
        >>>b = gmpy.mpz(2**177 149-1)
        >>>a==b
        True
        >>>print '%d' % (b)
        >
        Traceback (most recent call last):
        File "<pyshell#4 >", line 1, in <module>
        print '%d' % (b)
        TypeError: int argument required
        >
        So although the comparison operator is smart enough to realize
        the equivalency of numeric types and do the type conversion,
        the print statement isn't so smart.
        This is up to the gmpy designers/writers/maintainers. Anyone writing a
        class chooses which features to implement, which ones to omit, how to
        implement them, etc. The code may contain bugs, may not be efficient, may
        not behave exactly as the users expect, may not have anticipated all usage
        scenarios, a long etc. In this case, probably the gmpy writers have chosen
        not to allow to convert to int, and they may have good reasons to not do
        that (I don't know what platform are you working in, but I feel that your
        b object is somewhat larger than sys.maxint...).
        >Otherwise, objects of different builtin types always compare
        >unequal, and are ordered consistently but arbitrarily. You can control
        >comparison behavior of objects of non-builtin types by defining a
        >__cmp__
        >method or rich comparison methods like __gt__, described in section
        >3.4."
        >>
        >I hope this helps a bit. Your performance issues don't have to do with
        >the
        >*definition* of equal or not equal,
        >
        I didn't say that, I said the performance issues were related
        to type conversion. Can you explain how the "definition " of
        equal does not involve type conversion?
        There is no type conversion involved for user defined classes, *unless*
        the class writer chooses to do so.
        Let's invent some new class Number; they can be added and have basic
        str/repr support

        pyclass Number(object):
        .... def __init__(self, value): self.value=valu e
        .... def __add__(self, other): return Number(self.val ue+other.value)
        .... def __str__(self): return str(self.value)
        .... def __repr__(self): return 'Number(%s)' % self.value
        ....
        pyx = Number(2)
        pyy = Number(3)
        pyz = x+y
        pyz
        Number(5)
        pyz == 5
        False
        py5 == z
        False
        pyz == Number(5)
        False
        pyint(z)
        Traceback (most recent call last):
        File "<stdin>", line 1, in ?
        TypeError: int() argument must be a string or a number
        py"%d" % z
        Traceback (most recent call last):
        File "<stdin>", line 1, in ?
        TypeError: int argument required

        You can't compare them to anything, convert to integer, still nothing.
        Let's add "int conversion" first:

        pyNumber.__int_ _ = lambda self: int(self.value)
        pyint(z)
        5
        py"%d" % z
        '5'
        pyz == 5
        False
        py5 == z
        False

        Ok, a Number knows how to convert itself to integer, but still can't be
        compared successfully to anything. (Perhaps another language would try to
        convert automagically z to int, to compare against 5, but not Python).
        Let's add basic comparison support:

        pyNumber.__cmp_ _ = lambda self, other: cmp(self.value, other.value)
        pyz == Number(5)
        True
        pyz Number(7)
        False
        pyz == z
        True
        pyz == 5
        Traceback (most recent call last):
        File "<stdin>", line 1, in ?
        File "<stdin>", line 1, in <lambda>
        AttributeError: 'int' object has no attribute 'value'

        Now, a Number can be compared to another Number, but still not compared to
        integers. Let's make the comparison a bit smarter (uhm, I'll write it as a
        regular function because it's getting long...)

        pydef NumberCmp(self, other):
        .... if isinstance(othe r, Number): return cmp(self.value, other.value)
        .... else: return cmp(self.value, other)
        ....
        pyNumber.__cmp_ _ = NumberCmp
        pyz == 5
        True
        pyz == 6
        False
        py5 == z
        True

        As you can see, until I wrote some code explicitely to do the comparison,
        and allow other types of comparands, Python will not "convert" anything.
        If you find that some class appears to do a type conversion when comparing
        instances, it's because the class writer has explicitely coded it that
        way, not because Python does the conversion automagically.
        >only with how someone decided to write the mpz class.
        I'm beginning to think there's a problem there.
        Yes: you don't recognize that gmpy is not a builtin package, it's an
        external package, and its designers/writers/implementors/coders/whatever
        decide how it will behave, not Python itself nor the Python developers.

        --
        Gabriel Genellina

        Comment

        • Steve Holden

          #34
          Re: Interesting list Validity (True/False)

          mensanator@aol. com wrote:
          On May 12, 11:02�pm, Steven D'Aprano
          [ ... ]
          >
          But you can't trust a==d returning True to mean a and d are
          "equal". To say the comparison means the two objects are
          equal is misleading, in other words, wrong. It only takes one
          turd to spoil the whole punchbowl.
          >
          Unfortunately that is the very *definition* of "equal".
          >gmpy.mpz(1) on the other hand, is both a numeric type and a custom class.
          >It is free to define equal any way that makes sense, and it treats itself
          >as a numeric type and therefore says that it is equal to 1, just like 1.0
          >and 1+0j are equal to 1.
          >
          They are equal in the mathematical sense, but not otherwise.
          And to think that makes no difference is to be naive.
          >
          Perhaps so, but you are a long way from the original question now!

          regards
          Steve
          --
          Steve Holden +1 571 484 6266 +1 800 494 3119
          Holden Web LLC/Ltd http://www.holdenweb.com
          Skype: holdenweb http://del.icio.us/steve.holden
          ------------------ Asciimercial ---------------------
          Get on the web: Blog, lens and tag your way to fame!!
          holdenweb.blogs pot.com squidoo.com/pythonology
          tagged items: del.icio.us/steve.holden/python
          All these services currently offer free registration!
          -------------- Thank You for Reading ----------------

          Comment

          • Steven D'Aprano

            #35
            Re: Interesting list Validity (True/False)

            On Mon, 14 May 2007 11:41:21 -0700, mensanator@aol. com wrote:
            On May 13, 8:24 am, Steven D'Aprano
            <s...@REMOVE.TH IS.cybersource. com.auwrote:
            >On Sat, 12 May 2007 21:50:12 -0700, mensana...@aol. com wrote:
            >
            I intended to reply to this yesterday, but circumstances (see timeit
            results) prevented it.
            >
            Actually, it's this statement that's non-sensical.
            >>
            <quote>
            "if arg==True" tests whether the object known as arg is equal to
            the object known as True.
            </quote>
            >>
            >Not at all, it makes perfect sense. X == Y always tests whether the
            >argument X is equal to the object Y regardless of what X and Y are.
            >>
            Except for the exceptions, that's why the statement is wrong.
            >>
            >But there are no exceptions.
            >
            <quote emphasis added>
            Sec 2.2.3:
            Objects of different types, *--->except<---* different numeric types and
            different string types, never compare equal; </quote>
            Yes, and all swans are white, except for the black swans from Australia,
            but we're not talking about swans, nor are we talking about objects of
            different type comparing unequal, we're talking about whether X == Y
            means X is equal to Y.

            THERE ARE NO EXCEPTIONS TO THIS, BECAUSE IT IS TRUE BY DEFINITION.

            In Python, the meaning of "equal" is nothing more and nothing less than
            "does X == Y return True?". End of story, there is nothing more to
            discuss. If it returns True, they are equal. If it doesn't, they aren't.

            If you want to drag in non-Python meanings of "equal", you are wrong to
            do so. "Lizzie Windsor", "Queen Elizabeth the Second", "the Queen of
            England" and "Her Royal Majesty, Queen Elizabeth II" are all equal in the
            sense that they refer to the same person, but it would be crazy to expect
            Python to compare those strings equal.

            If you want to complain that lists and tokens should compare equal if
            their contents are the same, that's a different issue. I don't believe
            you'll have much support for that.

            If you want to complain that numeric types shouldn't compare equal, so
            that 1.0 != 1 != 1L != gmpy.mpz(1), that's also a different issue. I
            believe you'll have even less support for that suggestion.

            [snip]

            No, they are not "equal".
            >>
            >Of course they are. It says so right there: "a equals d" is true.
            >
            Ok, but they are an exception to the rule "different types compare
            False".
            You are only quoting part of the rule. The rule says that numeric types
            and strings are not included in the "different types" clause. If you
            quote the full rule, you will see that it is not an exception to the
            rule, it matches perfectly.

            Although, the rule as given is actually incomplete, because it only
            applies to built-in types. It does not apply to classes, because the
            class designer has complete control over the behaviour of his class. If
            the designer wants his class to compare equal to lists on Wednesdays and
            unequal on other days, he can. (That would be a stupid thing to do, but
            possible.)


            [snip]
            The ints
            ALWAYS have to be coerced to mpzs to perform arithmetic and this
            takes time...LOTS of it.
            >>
            >Really? Just how much time?
            >
            Can't say, had to abort the following. Returns the count of n/2 and 3n+1
            operations [1531812, 854697].
            Maybe you should use a test function that isn't so insane then. Honestly,
            if you want to time something, time something that actually completes!
            You don't gain any accuracy by running a program for twenty hours instead
            of twenty minutes.

            [snip functions generating the Collatz sequence]

            >timeit.Timer(" x == y", "import gmpy; x = 1; y = gmpy.mpz(1)").r epeat()
            >timeit.Timer(" x == y", "x = 1; y = 1").repeat()
            >>
            >I don't have gmpy installed here,
            >
            Good Lord! How do you solve a Linear Congruence? :-)
            In my head of course. Don't you?

            *wink*

            >so I can't time it, but I look forward to seeing the results, if you
            >would be so kind.
            >
            I had a lot of trouble with this, but I think I finally got a handle on
            it. I had to abort the previous test after 20+ hours and abort a second
            test (once I figured out to do your example) on another machine after
            14+ hours. I had forgotten just how significant the difference is.
            >
            import timeit
            >
            ## t = timeit.Timer("a == b", "a = 1; b = 1") ## u =
            timeit.Timer("c == d", "import gmpy; c = 1; d = gmpy.mpz(1)")
            ## t.repeat()
            ## [0.2231741743713 2372, 0.2251931460562 7253, 0.2247458825074 1367] ##
            u.repeat()
            ## [0.5994381967540 5763, 0.5962260566636 246, 0.6012292065052 9466]

            Comparisons between ints take about 0.2 microseconds, compared to about
            0.6 microseconds for small gmpy.mpz values. That's an optimization worth
            considering, but certainly not justifying your claim that one should
            NEVER compare an int and a mpz "in a loop". If the rest of the loop takes
            five milliseconds, who cares about a fraction of a microsecond difference?

            Unfortunately, this is not a very useful test, since mpz coercion
            appears to vary ny the size of the number involved.
            No, it is a very useful test. It's not an EXHAUSTIVE test.

            (By the way, you're not testing coercion. You're testing the time it
            takes to compare the two. There may or may not be any coercion involved.)

            Although changing t to
            >
            ## t = timeit.Timer("a == b", "a = 2**177149-1; b = 2**177149-1")
            >
            still produces tractable results
            ## t.repeat()
            ## [36.323597552202 841, 34.727026758987 506, 34.574566320579 862]
            About 36 microseconds per comparison, for rather large longints.

            the same can't be said for mpz coercion:
            >
            ## u = timeit.Timer("c == d", "import gmpy; c = 2**177149-1; d =
            gmpy.mpz(2**177 149-1)")
            ## u.repeat()
            ## *ABORTED after 14 hours*
            This tells us that a comparison between large longints and large gmpz.mpz
            vales take a minimum of 14 hours divided by three million, or roughly 17
            milliseconds each. That's horribly expensive if you have a lot of them.

            It isn't clear _why_ the comparison takes so long.


            [snip]
            And, just for laughs, I compared mpzs to mpzs,
            >
            s = 'import gmpy; a = gmpy.mpz(%d); b = gmpy.mpz(%d)' % (n,n)
            >
            which ended up faster than comparing ints to ints.
            I'm hardly surprised. If speed is critical, gmpy is likely to be faster
            than anything you can do in pure Python.



            [snip]

            >Even if it is terribly slow, that's just an implementation detail. What
            >happens when Python 2.7 comes out (or Python 3.0 or Python 99.78) and
            >coercion from int to mpz is lightning fast? Would you then say "Well,
            >int(1) and mpz(1) used to be unequal, but now they are equal?".
            >
            Are you saying I should be unconcerned about implementation details?
            That it's silly of me to be concerned about implementation side effects
            due to mis-matched types?
            Of course not. But the discussion isn't about optimization, that's just
            an irrelevant side-track.

            >Me, I'd say they always were equal, but previously it used to be slow
            >to coerce one to the other.
            >
            So, when you're giving advice to the OP you don't feel any need to point
            this out? That's all I'm trying to do, supply some "yes, but you should
            be aware of..." commentary.
            Why on Earth would I need to mention gmpy.mpz()? Does the OP even use
            gmpy? You were the one who brought gmpy into the discussion, not him. Why
            not give him a lecture about not repeatedly adding strings together, or
            using << instead of multiplication by two, or any other completely
            irrelevant optimization? My favorite, by the way, is that you can save
            anything up to an hour of driving time by avoiding Hoddle Street during
            peak hour and using the back-streets through Abbotsford, next to Yarra
            Bend Park and going under the Eastern Freeway. Perhaps I should have
            raised that as well?

            >In any case, what you describe is a local optimization. Its probably a
            >good optimization, but in no way, shape or form does it imply that
            >mpz(1) is not equal to 1.
            >
            It's a different type. It is an exception to the "different types
            compare False" rule.
            What does this have to do with your ridiculous claim that mpz(1) is not
            equal to 1? It clearly is equal.

            That exception is not without cost, the type mis-match
            causes coercion.
            Any comparison has a cost. Sometimes its a lot, sometimes a little. That
            has nothing to do with equality.


            >There's nothing false about it. Ask any mathematician, does 1 equal
            >1.0, and they will say "of course".
            >
            And if you ask any mathematician, he'll say that (1,) is equal to [1].
            I'd like to find the mathematician who says that. The first thing he'd
            say is "what is this (1,) notation you are using?" and the second thing
            he'd ask is "equal in what sense?".

            Perhaps you should ask a mathematician if the set {1, 2} and the vector
            [1, 2] are equal, and if either of them are equal to the coordinate pair
            (1, 2).

            That's the difference between a mathematician and a programmer. A
            programmer will say "of course not, the int has to be coered."
            A C programmer maybe.

            [snip]
            >Numeric values are automatically coerced because that's more practical.
            >That's a design decision, and it works well.
            >
            And I'm not saying it shouldn't be that way. But when I wrote my Collatz
            Functions library, I wasn't aware of the performance issues when doing
            millions of loop cycles with numbers having millions of digits. I only
            found that out later. Would I have gotten a proper answer on this
            newgroup had I asked here? Sure doesn't look like it.
            If you had asked _what_? Unless you tell me what question you asked, how
            can anyone guess what answer you would have received?

            If you had asked a question about optimization, you surely would have
            received an answer about optimization.

            If you asked about string concatenation, you would have received a
            question about string concatenation.

            If you had asked a question about inheritance, you would have received an
            answer about inheritance.

            See the pattern?

            BTW, in reviewing my Collatz Functions library, I noticed a coercion I
            had overlooked, so as a result of this discussion, my library is now
            slightly faster. So some good comes out of this argument after all.
            >
            >
            >As for gmpy.mpz, since equality tests are completely under the control
            >of the class author, the gmpy authors obviously wanted mpz values to
            >compare equal with ints.
            >
            And they chose to do a silent coercion rather than raise a type
            exception.
            It says right in the gmpy documentation that this coercion will be
            performed.
            What it DOESN'T say is what the implications of this silent coercion
            are.
            OF COURSE a coercion takes time. This is Python, where everything is a
            rich object, not some other language where a coercion merely tells the
            compiler to consider bytes to be some other type. If you need your hand-
            held to the point that you need somebody to tell you that operations take
            time, maybe you need to think about changing professions.

            The right way to do this is to measure first, then worry about
            optimizations. The wrong way is to try to guess the bottlenecks ahead of
            time. The worse way is to expect other people to tell you were your
            bottlenecks are ahead of time.


            >
            >
            >Since both lists and tuples are containers, neither are strings or
            >numeric types, so the earlier rule applies: they are different
            >types, so they can't be equal.
            >>
            But you can't trust a==d returning True to mean a and d are "equal".
            >>
            >What does it mean then?
            >
            It means they are mathematically equivalent, which is not the same as
            being programatically equivalent. Mathematical equivalency is what most
            people want most of the time.
            I think that by "most people", you mean you.

            Not all of the people all of the time,
            however. For example, I can calculate my Hailstone Function parameters
            using either a list or a tuple:
            >
            >>>import collatz_functio ns as cf
            >>>print cf.calc_xyz([1,2])
            (mpz(8), mpz(9), mpz(5))
            >>>print cf.calc_xyz((1, 2))
            (mpz(8), mpz(9), mpz(5))
            >
            But [1,2]==(1,2) yields False, so although they are not equal, they ARE
            interchangeable in this application because they are mathematically
            equivalent.
            No, they aren't mathematically equivalent, because Python data structures
            aren't mathematical entities. (They may be _similar to_ mathematical
            entities, but they aren't the same. Just ask a mathematician about the
            difference between a Real number and a float.)

            They are, however, both sequences, and so if your function expects any
            sequence, they will both work.


            [snip]
            >I never said that there was no efficiency differences. Comparing X with
            >Y might take 0.02ms or it could take 2ms depending on how much work
            >needs to be done. I just don't understand why you think that has a
            >bearing on whether they are equal or not.
            >
            The bearing it has matters when you're writing a function library that
            you want to execute efficiently.
            Which is true, but entirely irrelevant to the question in hand, which is
            "are they equal?".



            --
            Steven.

            Comment

            • mensanator@aol.com

              #36
              Re: Interesting list Validity (True/False)

              On May 15, 9:23�pm, Steven D'Aprano
              <ste...@REMOVE. THIS.cybersourc e.com.auwrote:
              On Mon, 14 May 2007 11:41:21 -0700, mensana...@aol. com wrote:
              On May 13, 8:24 am, Steven D'Aprano
              <s...@REMOVE.TH IS.cybersource. com.auwrote:
              On Sat, 12 May 2007 21:50:12 -0700, mensana...@aol. com wrote:
              >
              I intended to reply to this yesterday, but circumstances (see timeit
              results) prevented it.
              >
              Actually, it's this statement that's non-sensical.
              >
              <quote>
              "if arg==True" tests whether the object known as arg is equalto
              the object known as True.
              </quote>
              >
              Not at all, it makes perfect sense. X == Y always tests whetherthe
              argument X is equal to the object Y regardless of what X and Y are.
              >
              Except for the exceptions, that's why the statement is wrong.
              >
              But there are no exceptions.
              >
              <quote emphasis added>
              Sec 2.2.3:
              Objects of different types, *--->except<---* different numeric types and
              different string types, never compare equal; </quote>
              >
              Yes, and all swans are white, except for the black swans from Australia,
              but we're not talking about swans, nor are we talking about objects of
              different type comparing unequal, we're talking about whether X == Y
              means X is equal to Y.
              >
              THERE ARE NO EXCEPTIONS TO THIS, BECAUSE IT IS TRUE BY DEFINITION.
              >
              In Python, the meaning of "equal" is nothing more and nothing less than
              "does X == Y return True?". End of story, there is nothing more to
              discuss. If it returns True, they are equal. If it doesn't, they aren't.
              >
              If you want to drag in non-Python meanings of "equal", you are wrong to
              do so. "Lizzie Windsor", "Queen Elizabeth the Second", "the Queen of
              England" and "Her Royal Majesty, Queen Elizabeth II" are all equal in the
              sense that they refer to the same person, but it would be crazy to expect
              Python to compare those strings equal.
              >
              If you want to complain that lists and tokens should compare equal if
              their contents are the same, that's a different issue. I don't believe
              you'll have much support for that.
              >
              If you want to complain that numeric types shouldn't compare equal, so
              that 1.0 != 1 != 1L != gmpy.mpz(1), that's also a different issue. I
              believe you'll have even less support for that suggestion.
              >
              [snip]
              >
              No, they are not "equal".
              >
              Of course they are. It says so right there: "a equals d" is true.
              >
              Ok, but they are an exception to the rule "different types compare
              False".
              >
              You are only quoting part of the rule. The rule says that numeric types
              and strings are not included in the "different types" clause. If you
              quote the full rule, you will see that it is not an exception to the
              rule, it matches perfectly.
              Uh...ok, I get it...I think.

              I always thought that when someone said "all primes are
              odd except 2" it meant that 2 was was an exception.
              But since the rule specifically says 2 is an exception,
              it's not an exception.
              >
              Although, the rule as given is actually incomplete, because it only
              applies to built-in types. It does not apply to classes, because the
              class designer has complete control over the behaviour of his class. If
              the designer wants his class to compare equal to lists on Wednesdays and
              unequal on other days, he can. (That would be a stupid thing to do, but
              possible.)
              >
              [snip]
              >
              The ints
              ALWAYS have to be coerced to mpzs to perform arithmetic and this
              takes time...LOTS of it.
              >
              Really? Just how much time?
              >
              Can't say, had to abort the following. Returns the count of n/2 and 3n+1
              operations [1531812, 854697].
              >
              Maybe you should use a test function that isn't so insane then. Honestly,
              if you want to time something, time something that actually completes!
              You don't gain any accuracy by running a program for twenty hours instead
              of twenty minutes.
              Actually, I misunderstood the timeit tests, didn't quite realize the
              difference between .timeit() and .repeat(). And although that number
              may look insane, it's one I'm quite familiar with so I can tell that
              everything's working right. My Collatz research tends to be on the
              fringe, in places where angels fear to tread.
              >
              [snip functions generating the Collatz sequence]
              >
              timeit.Timer("x == y", "import gmpy; x = 1; y = gmpy.mpz(1)").r epeat()
              timeit.Timer("x == y", "x = 1; y = 1").repeat()
              >
              I don't have gmpy installed here,
              >
              Good Lord! How do you solve a Linear Congruence? :-)
              >
              In my head of course. Don't you?
              >
              *wink*
              >
              so I can't time it, but I look forward to seeing the results, if you
              would be so kind.
              >
              I had a lot of trouble with this, but I think I finally got a handle on
              it. I had to abort the previous test after 20+ hours and abort a second
              test (once I figured out to do your example) on another machine after
              14+ hours. I had forgotten just how significant the difference is.
              >
              import timeit
              >
              ##    t = timeit.Timer("a == b", "a = 1; b = 1") ##    u =
              timeit.Timer("c == d", "import gmpy; c = 1; d = gmpy.mpz(1)")
              ##    t.repeat()
              ##    [0.2231741743713 2372, 0.2251931460562 7253, 0.2247458825074 1367] ##
                 u.repeat()
              ##    [0.5994381967540 5763, 0.5962260566636 246, 0.6012292065052 9466]
              >
              Comparisons between ints take about 0.2 microseconds, compared to about
              0.6 microseconds for small gmpy.mpz values. That's an optimization worth
              considering, but certainly not justifying your claim that one should
              NEVER compare an int and a mpz "in a loop". If the rest of the loop takes
              five milliseconds, who cares about a fraction of a microsecond difference?
              >
              Unfortunately, this is not a very useful test, since mpz coercion
              appears to vary ny the size of the number involved.
              >
              No, it is a very useful test. It's not an EXHAUSTIVE test.
              >
              (By the way, you're not testing coercion. You're testing the time it
              takes to compare the two. There may or may not be any coercion involved.)
              But isn't the difference between t.repeat() and u.repeat() due to
              coercion?
              >
              Although changing t to
              >
              ##    t = timeit.Timer("a == b", "a = 2**177149-1; b = 2**177149-1")
              >
              still produces tractable results
              ##    t.repeat()
              ##    [36.323597552202 841, 34.727026758987 506, 34.574566320579 862]
              >
              About 36 microseconds per comparison, for rather large longints.
              >
              the same can't be said for mpz coercion:
              >
              ##    u = timeit.Timer("c == d", "import gmpy; c = 2**177149-1; d =
              gmpy.mpz(2**177 149-1)")
              ##    u.repeat()
              ##    *ABORTED after 14 hours*
              >
              This tells us that a comparison between large longints and large gmpz.mpz
              vales take a minimum of 14 hours divided by three million,
              I thought it was 14 hours divided by 3. I said I didn't quite
              understand how timeit worked.
              or roughly 17
              milliseconds each. That's horribly expensive if you have a lot of them.
              Yeah, and that will be the case for large numbers which is
              why I chose that insane number. In the Collatz test, that
              works out to about 1.7 million loop cycles. Run time is
              logarithmic to number size, so truly insane values still have
              tractable run times. Provided you don't mistakenly ask for
              3 million tests thinking it's 3.
              >
              It isn't clear _why_ the comparison takes so long.
              I'm thinking there may be something wrong.
              >
              [snip]
              >
              And, just for laughs, I compared mpzs to mpzs,
              >
                  s = 'import gmpy; a = gmpy.mpz(%d); b = gmpy.mpz(%d)' % (n,n)
              >
              which ended up faster than comparing ints to ints.
              >
              I'm hardly surprised. If speed is critical, gmpy is likely to be faster
              than anything you can do in pure Python.
              >
              [snip]
              >
              Even if it is terribly slow, that's just an implementation detail. What
              happens when Python 2.7 comes out (or Python 3.0 or Python 99.78) and
              coercion from int to mpz is lightning fast? Would you then say "Well,
              int(1) and mpz(1) used to be unequal, but now they are equal?".
              >
              Are you saying I should be unconcerned about implementation details?
              That it's silly of me to be concerned about implementation side effects
              due to mis-matched types?
              >
              Of course not. But the discussion isn't about optimization, that's just
              an irrelevant side-track.
              >
              Me, I'd say they always were equal, but previously it used to be slow
              to coerce one to the other.
              >
              So, when you're giving advice to the OP you don't feel any need to point
              this out? That's all I'm trying to do, supply some "yes, but you should
              be aware of..." commentary.
              >
              Why on Earth would I need to mention gmpy.mpz()? Does the OP even use
              gmpy? You were the one who brought gmpy into the discussion, not him. Why
              not give him a lecture about not repeatedly adding strings together, or
              using << instead of multiplication by two, or any other completely
              irrelevant optimization? My favorite, by the way, is that you can save
              anything up to an hour of driving time by avoiding Hoddle Street during
              peak hour and using the back-streets through Abbotsford, next to Yarra
              Bend Park and going under the Eastern Freeway. Perhaps I should have
              raised that as well?
              >
              In any case, what you describe is a local optimization. Its probably a
              good optimization, but in no way, shape or form does it imply that
              mpz(1) is not equal to 1.
              >
              It's a different type. It is an exception to the "different types
              compare False" rule.
              >
              What does this have to do with your ridiculous claim that mpz(1) is not
              equal to 1? It clearly is equal.
              >
              That exception is not without cost, the type mis-match
              causes coercion.
              >
              Any comparison has a cost. Sometimes its a lot, sometimes a little. That
              has nothing to do with equality.
              >
              There's nothing false about it. Ask any mathematician, does 1 equal
              1.0, and they will say "of course".
              >
              And if you ask any mathematician, he'll say that (1,) is equal to [1].
              >
              I'd like to find the mathematician who says that. The first thing he'd
              say is "what is this (1,) notation you are using?" and the second thing
              he'd ask is "equal in what sense?".
              >
              Perhaps you should ask a mathematician if the set {1, 2} and the vector
              [1, 2] are equal, and if either of them are equal to the coordinate pair
              (1, 2).
              >
              That's the difference between a mathematician and a programmer. A
              programmer will say "of course not, the int has to be coered."
              >
              A C programmer maybe.
              >
              [snip]
              >
              Numeric values are automatically coerced because that's more practical.
              That's a design decision, and it works well.
              >
              And I'm not saying it shouldn't be that way. But when I wrote my Collatz
              Functions library, I wasn't aware of the performance issues when doing
              millions of loop cycles with numbers having millions of digits. I only
              found that out later. Would I have gotten a proper answer on this
              newgroup had I asked here? Sure doesn't look like it.
              >
              If you had asked _what_? Unless you tell me what question you asked, how
              can anyone guess what answer you would have received?
              >
              If you had asked a question about optimization, you surely would have
              received an answer about optimization.
              >
              If you asked about string concatenation, you would have received a
              question about string concatenation.
              >
              If you had asked a question about inheritance, you would have received an
              answer about inheritance.
              >
              See the pattern?
              >
              BTW, in reviewing my Collatz Functions library, I noticed a coercion I
              had overlooked, so as a result of this discussion, my library is now
              slightly faster. So some good comes out of this argument after all.
              >
              As for gmpy.mpz, since equality tests are completely under the control
              of the class author, the gmpy authors obviously wanted mpz values to
              compare equal with ints.
              >
              And they chose to do a silent coercion rather than raise a type
              exception.
              It says right in the gmpy documentation that this coercion will be
              performed.
              What it DOESN'T say is what the implications of this silent coercion
              are.
              >
              OF COURSE a coercion takes time. This is Python, where everything is a
              rich object, not some other language where a coercion merely tells the
              compiler to consider bytes to be some other type. If you need your hand-
              held to the point that you need somebody to tell you that operations take
              time, maybe you need to think about changing professions.
              >
              The right way to do this is to measure first, then worry about
              optimizations. The wrong way is to try to guess the bottlenecks ahead of
              time. The worse way is to expect other people to tell you were your
              bottlenecks are ahead of time.
              >
              >
              >
              Since both lists and tuples are containers, neither are strings or
              numeric types, so the earlier rule applies: they are different
              types, so they can't be equal.
              >
              But you can't trust a==d returning True to mean a and d are "equal".
              >
              What does it mean then?
              >
              It means they are mathematically equivalent, which is not the same as
              being programatically equivalent. Mathematical equivalency is what most
              people want most of the time.
              >
              I think that by "most people", you mean you.
              >
              Not all of the people all of the time,
              however. For example, I can calculate my Hailstone Function parameters
              using either a list or a tuple:
              >
              >>import collatz_functio ns as cf
              >>print cf.calc_xyz([1,2])
              (mpz(8), mpz(9), mpz(5))
              >>print cf.calc_xyz((1, 2))
              (mpz(8), mpz(9), mpz(5))
              >
              But [1,2]==(1,2) yields False, so although they are not equal, theyARE
              interchangeable in this application because they are mathematically
              equivalent.
              >
              No, they aren't mathematically equivalent, because Python data structures
              aren't mathematical entities. (They may be _similar to_ mathematical
              entities, but they aren't the same. Just ask a mathematician about the
              difference between a Real number and a float.)
              >
              They are, however, both sequences, and so if your function expects any
              sequence, they will both work.
              >
              [snip]
              >
              I never said that there was no efficiency differences. Comparing X with
              Y might take 0.02ms or it could take 2ms depending on how much work
              needs to be done. I just don't understand why you think that has a
              bearing on whether they are equal or not.
              >
              The bearing it has matters when you're writing a function library that
              you want to execute efficiently.
              >
              Which is true, but entirely irrelevant to the question in hand, which is
              "are they equal?".
              Hey, here's an idea...let's forget the whole thing.
              >
              --
              Steven.

              Comment

              • mensanator@aol.com

                #37
                Re: Interesting list Validity (True/False)

                On May 15, 7:07 pm, "Gabriel Genellina" <gagsl-...@yahoo.com.a r>
                wrote:
                En Tue, 15 May 2007 14:01:20 -0300, mensana...@aol. com
                <mensana...@aol .comescribió:
                >
                On May 15, 12:30 am, "Gabriel Genellina" <gagsl-...@yahoo.com.a r>
                wrote:
                And said section 5.9 should be updated too: "The objects need not have
                the
                same type. If both are numbers or strings, they are converted to a
                common
                type.
                >
                Except when they aren't.
                >
                I think you don't get the difference between a builtin object, fully under
                the Python developers' control, and a user defined class that can behave
                arbitrarily at wish of its writer and for which the Python documentation
                barely can say a word.
                The docs say how will the Python interpreter try to compare objects
                (invoke the rich comparison methods, invoke __cmp__, etc) and how the
                *builtin* objects behave. For other objects, it's up to the object
                *writer* to provide such methods, and he can do whatever he wishes:
                >
                pyclass Reversed(int):
                ... def __lt__(self, other): return cmp(int(self),o ther)>0
                ... def __gt__(self, other): return cmp(int(self),o ther)<0
                ... def __le__(self, other): return cmp(int(self),o ther)>=0
                ... def __ge__(self, other): return cmp(int(self),o ther)<=0
                ...
                py>
                pyj=Reversed(6)
                pyj==6
                True
                pyj>5
                False
                pyj>10
                True
                pyj<=5
                True
                >
                You can't blame Python for this.
                >
                >>import gmpy
                >>a = 2**177149-1
                >>b = gmpy.mpz(2**177 149-1)
                >>a==b
                True
                >>print '%d' % (b)
                >
                Traceback (most recent call last):
                File "<pyshell#4 >", line 1, in <module>
                print '%d' % (b)
                TypeError: int argument required
                >
                So although the comparison operator is smart enough to realize
                the equivalency of numeric types and do the type conversion,
                the print statement isn't so smart.
                >
                This is up to the gmpy designers/writers/maintainers. Anyone writing a
                class chooses which features to implement, which ones to omit, how to
                implement them, etc. The code may contain bugs, may not be efficient, may
                not behave exactly as the users expect, may not have anticipated all usage
                scenarios, a long etc. In this case, probably the gmpy writers have chosen
                not to allow to convert to int, and they may have good reasons to not do
                that (I don't know what platform are you working in, but I feel that your
                b object is somewhat larger than sys.maxint...).
                Then how does this work?
                >>print '%d' % (long(gmpy.mpz( 2**177149-1)))
                1454...<53320 digits snipped>...3311

                I honestly don't understand why there's a problem here.
                If print can handle arbitrary precision longs without
                a problem, why does it fail on mpzs sys.maxint?
                If the gmpy writers are not allowing the conversion,
                then why do small mpz values work? Something smells
                inconsistent here.

                How is it that
                >>print '%d' % (1.0)
                1

                doesn't make a type mismatch? Obviously, the float
                got changed to an int and this had nothing to do with
                gmpy. Is it the print process responsible for doing
                the conversion? Maybe I should say invoking the
                conversion? Maybe the gmpy call tries to literally
                convert to an integer rather than sneakily substitute
                a long?

                How else can this phenomena be explained?
                Otherwise, objects of different builtin types always compare
                unequal, and are ordered consistently but arbitrarily. You can control
                comparison behavior of objects of non-builtin types by defining a
                __cmp__
                method or rich comparison methods like __gt__, described in section
                3.4."
                >
                I hope this helps a bit. Your performance issues don't have to do with
                the
                *definition* of equal or not equal,
                >
                I didn't say that, I said the performance issues were related
                to type conversion. Can you explain how the "definition " of
                equal does not involve type conversion?
                >
                There is no type conversion involved for user defined classes, *unless*
                the class writer chooses to do so.
                Let's invent some new class Number; they can be added and have basic
                str/repr support
                >
                pyclass Number(object):
                ... def __init__(self, value): self.value=valu e
                ... def __add__(self, other): return Number(self.val ue+other.value)
                ... def __str__(self): return str(self.value)
                ... def __repr__(self): return 'Number(%s)' % self.value
                ...
                pyx = Number(2)
                pyy = Number(3)
                pyz = x+y
                pyz
                Number(5)
                pyz == 5
                False
                py5 == z
                False
                pyz == Number(5)
                False
                pyint(z)
                Traceback (most recent call last):
                File "<stdin>", line 1, in ?
                TypeError: int() argument must be a string or a number
                py"%d" % z
                Traceback (most recent call last):
                File "<stdin>", line 1, in ?
                TypeError: int argument required
                >
                You can't compare them to anything, convert to integer, still nothing.
                Let's add "int conversion" first:
                >
                pyNumber.__int_ _ = lambda self: int(self.value)
                pyint(z)
                5
                py"%d" % z
                '5'
                pyz == 5
                False
                py5 == z
                False
                >
                Ok, a Number knows how to convert itself to integer, but still can't be
                compared successfully to anything. (Perhaps another language would try to
                convert automagically z to int, to compare against 5, but not Python).
                Let's add basic comparison support:
                >
                pyNumber.__cmp_ _ = lambda self, other: cmp(self.value, other.value)
                pyz == Number(5)
                True
                pyz Number(7)
                False
                pyz == z
                True
                pyz == 5
                Traceback (most recent call last):
                File "<stdin>", line 1, in ?
                File "<stdin>", line 1, in <lambda>
                AttributeError: 'int' object has no attribute 'value'
                >
                Now, a Number can be compared to another Number, but still not compared to
                integers. Let's make the comparison a bit smarter (uhm, I'll write it as a
                regular function because it's getting long...)
                >
                pydef NumberCmp(self, other):
                ... if isinstance(othe r, Number): return cmp(self.value, other.value)
                ... else: return cmp(self.value, other)
                ...
                pyNumber.__cmp_ _ = NumberCmp
                pyz == 5
                True
                pyz == 6
                False
                py5 == z
                True
                >
                As you can see, until I wrote some code explicitely to do the comparison,
                and allow other types of comparands, Python will not "convert" anything.
                If you find that some class appears to do a type conversion when comparing
                instances, it's because the class writer has explicitely coded it that
                way, not because Python does the conversion automagically.
                Ok, ok. But how does the subroutine that the class
                writer created to do the actual conversion get invoked?
                >
                only with how someone decided to write the mpz class.
                I'm beginning to think there's a problem there.
                >
                Yes: you don't recognize that gmpy is not a builtin package, it's an
                external package, and its designers/writers/implementors/coders/whatever
                decide how it will behave, not Python itself nor the Python developers.
                >
                --
                Gabriel Genellina

                Comment

                • Gabriel Genellina

                  #38
                  Re: Interesting list Validity (True/False)

                  En Wed, 16 May 2007 03:16:59 -0300, mensanator@aol. com
                  <mensanator@aol .comescribió:
                  On May 15, 7:07 pm, "Gabriel Genellina" <gagsl-...@yahoo.com.a r>
                  wrote:
                  >>>import gmpy
                  >>>a = 2**177149-1
                  >>>b = gmpy.mpz(2**177 149-1)
                  >>>a==b
                  True
                  >>>print '%d' % (b)
                  >>
                  Traceback (most recent call last):
                  File "<pyshell#4 >", line 1, in <module>
                  print '%d' % (b)
                  TypeError: int argument required
                  >>
                  So although the comparison operator is smart enough to realize
                  the equivalency of numeric types and do the type conversion,
                  the print statement isn't so smart.
                  >>
                  >This is up to the gmpy designers/writers/maintainers. Anyone writing a
                  >class chooses which features to implement, which ones to omit, how to
                  >implement them, etc. The code may contain bugs, may not be efficient,
                  >may
                  >not behave exactly as the users expect, may not have anticipated all
                  >usage
                  >scenarios, a long etc. In this case, probably the gmpy writers have
                  >chosen
                  >not to allow to convert to int, and they may have good reasons to not do
                  >that (I don't know what platform are you working in, but I feel that
                  >your
                  >b object is somewhat larger than sys.maxint...).
                  >
                  Then how does this work?
                  >
                  >>>print '%d' % (long(gmpy.mpz( 2**177149-1)))
                  1454...<53320 digits snipped>...3311
                  >
                  I honestly don't understand why there's a problem here.
                  If print can handle arbitrary precision longs without
                  a problem, why does it fail on mpzs sys.maxint?
                  If the gmpy writers are not allowing the conversion,
                  then why do small mpz values work? Something smells
                  inconsistent here.
                  Python (builtin) "integral numbers" come on two flavors: int and long.
                  ints correspond to the C `long` type usually, and have a limited range, at
                  least from -2**31 to 2**31-1; most operations have hardware support (or at
                  least it's up to the C compiler). Long integers are a totally different
                  type, they have unlimited range but are a lot slower, and all operations
                  must be done "by hand". See http://docs.python.org/ref/types.html

                  If you say "%d" % something, Python first tries to see if `something` is a
                  long integer -not to *convert* it to a long integer, just to see if the
                  object *is* a long integer. If it's a long, it's formatted accordingly.
                  If not, Python sees if `something` is a plain integer. If not, it sees if
                  it's a number (in this context, that means that the structure describing
                  its type contains a non-NULL tp_as_number member) and tries to *convert*
                  it to an integer. Notice that if the object whas not originally a long
                  integer, no attempt is made to convert it to a long using the nb_long
                  member - just a plain integer conversion is attempted.
                  It's at this stage that a large mpz object may fail - when its value can't
                  fit in a plain integer, it raises an OverflowError and the "%d" formatting
                  fails.
                  If you force a conversion to long integer, using long(mpz(...)) as above,
                  the % operator sees a long integer from start and it can be formatted
                  without problems.

                  I don't know if this asymmetric behavior is a design decision, a historic
                  relic, a change in protocol (is nb_int allowed now to return a
                  PyLongObject, but not before?), a "nobody cares" issue, or just a bug.
                  Perhaps someone else can give an opinion - and certainly I may be wrong, I
                  had never looked at the PyString_Format function internal details before
                  (thanks for providing an excuse!).

                  As a workaround you can always write "%d" % long(mpznumber) when you want
                  to print them (or perhaps "%s" % mpznumber, which might be faster).
                  How is it that
                  >
                  >>>print '%d' % (1.0)
                  1
                  >
                  doesn't make a type mismatch? Obviously, the float
                  got changed to an int and this had nothing to do with
                  gmpy. Is it the print process responsible for doing
                  the conversion? Maybe I should say invoking the
                  conversion? Maybe the gmpy call tries to literally
                  convert to an integer rather than sneakily substitute
                  a long?
                  Same as above: is the argument a long integer? no. is it a number? yes.
                  Convert to int. No errors? Apply format.

                  --
                  Gabriel Genellina

                  Comment

                  • mensanator@aol.com

                    #39
                    Re: Interesting list Validity (True/False)

                    On May 16, 4:12 am, "Gabriel Genellina" <gagsl-...@yahoo.com.a r>
                    wrote:
                    En Wed, 16 May 2007 03:16:59 -0300, mensana...@aol. com
                    <mensana...@aol .comescribió:
                    >
                    >
                    >
                    >
                    >
                    On May 15, 7:07 pm, "Gabriel Genellina" <gagsl-...@yahoo.com.a r>
                    wrote:
                    >>import gmpy
                    >>a = 2**177149-1
                    >>b = gmpy.mpz(2**177 149-1)
                    >>a==b
                    True
                    >>print '%d' % (b)
                    >
                    Traceback (most recent call last):
                    File "<pyshell#4 >", line 1, in <module>
                    print '%d' % (b)
                    TypeError: int argument required
                    >
                    So although the comparison operator is smart enough to realize
                    the equivalency of numeric types and do the type conversion,
                    the print statement isn't so smart.
                    >
                    This is up to the gmpy designers/writers/maintainers. Anyone writing a
                    class chooses which features to implement, which ones to omit, how to
                    implement them, etc. The code may contain bugs, may not be efficient,
                    may
                    not behave exactly as the users expect, may not have anticipated all
                    usage
                    scenarios, a long etc. In this case, probably the gmpy writers have
                    chosen
                    not to allow to convert to int, and they may have good reasons to not do
                    that (I don't know what platform are you working in, but I feel that
                    your
                    b object is somewhat larger than sys.maxint...).
                    >
                    Then how does this work?
                    >
                    >>print '%d' % (long(gmpy.mpz( 2**177149-1)))
                    1454...<53320 digits snipped>...3311
                    >
                    I honestly don't understand why there's a problem here.
                    If print can handle arbitrary precision longs without
                    a problem, why does it fail on mpzs sys.maxint?
                    If the gmpy writers are not allowing the conversion,
                    then why do small mpz values work? Something smells
                    inconsistent here.
                    >
                    Python (builtin) "integral numbers" come on two flavors: int and long.
                    ints correspond to the C `long` type usually, and have a limited range, at
                    least from -2**31 to 2**31-1; most operations have hardware support (or at
                    least it's up to the C compiler). Long integers are a totally different
                    type, they have unlimited range but are a lot slower, and all operations
                    must be done "by hand". Seehttp://docs.python.org/ref/types.html
                    >
                    If you say "%d" % something, Python first tries to see if `something` is a
                    long integer -not to *convert* it to a long integer, just to see if the
                    object *is* a long integer. If it's a long, it's formatted accordingly.
                    If not, Python sees if `something` is a plain integer. If not, it sees if
                    it's a number (in this context, that means that the structure describing
                    its type contains a non-NULL tp_as_number member) and tries to *convert*
                    it to an integer. Notice that if the object whas not originally a long
                    integer, no attempt is made to convert it to a long using the nb_long
                    member - just a plain integer conversion is attempted.
                    It's at this stage that a large mpz object may fail - when its value can't
                    fit in a plain integer, it raises an OverflowError and the "%d" formatting
                    fails.
                    If you force a conversion to long integer, using long(mpz(...)) as above,
                    the % operator sees a long integer from start and it can be formatted
                    without problems.
                    >
                    I don't know if this asymmetric behavior is a design decision, a historic
                    relic, a change in protocol (is nb_int allowed now to return a
                    PyLongObject, but not before?), a "nobody cares" issue, or just a bug.
                    Perhaps someone else can give an opinion - and certainly I may be wrong, I
                    had never looked at the PyString_Format function internal details before
                    (thanks for providing an excuse!).
                    Ah, thanks for the info, I know nothing about Python internals.

                    That implies that although this works:
                    >>print '%d' %(1234567890.0)
                    1234567890

                    this does not:
                    >>print '%d' %(1234567890123 4567890.0)
                    Traceback (most recent call last):
                    File "<pyshell#1 >", line 1, in <module>
                    print '%d' %(1234567890123 4567890.0)
                    TypeError: int argument required

                    So we can work around it by doing the long conversion
                    ourselves since print only knows how to invoke int conversion.
                    >>print '%d' %(long(12345678 901234567890.0) )
                    123456789012345 67168

                    which demonstartes the problem is not with gmpy.
                    >
                    As a workaround you can always write "%d" % long(mpznumber) when you want
                    to print them (or perhaps "%s" % mpznumber, which might be faster).
                    >
                    How is it that
                    >
                    >>print '%d' % (1.0)
                    1
                    >
                    doesn't make a type mismatch? Obviously, the float
                    got changed to an int and this had nothing to do with
                    gmpy. Is it the print process responsible for doing
                    the conversion? Maybe I should say invoking the
                    conversion? Maybe the gmpy call tries to literally
                    convert to an integer rather than sneakily substitute
                    a long?
                    >
                    Same as above: is the argument a long integer? no. is it a number? yes.
                    Convert to int. No errors? Apply format.
                    Thanks again, as long as I know why the behaviour is strange,
                    I know how to work around it
                    >
                    --
                    Gabriel Genellina

                    Comment

                    • Alex Martelli

                      #40
                      Re: Interesting list Validity (True/False)

                      Gabriel Genellina <gagsl-py2@yahoo.com.a rwrote:
                      >>import gmpy
                      >>a = 2**177149-1
                      >>b = gmpy.mpz(2**177 149-1)
                      >>a==b
                      True
                      >>print '%d' % (b)
                      Traceback (most recent call last):
                      File "<pyshell#4 >", line 1, in <module>
                      print '%d' % (b)
                      TypeError: int argument required

                      So although the comparison operator is smart enough to realize
                      the equivalency of numeric types and do the type conversion,
                      the print statement isn't so smart.
                      >
                      This is up to the gmpy designers/writers/maintainers. Anyone writing a
                      class chooses which features to implement, which ones to omit, how to
                      implement them, etc. The code may contain bugs, may not be efficient, may
                      not behave exactly as the users expect, may not have anticipated all usage
                      scenarios, a long etc. In this case, probably the gmpy writers have chosen
                      not to allow to convert to int, and they may have good reasons to not do
                      that (I don't know what platform are you working in, but I feel that your
                      b object is somewhat larger than sys.maxint...).
                      The gmpy designer, writer and maintainer (all in the singular -- that's
                      me) has NOT chosen anything of the sort. gmpy.mpz does implement
                      __int__ and __long__ -- but '%d'%somempzins tance chooses not to call
                      either of them. sys.maxint has nothing to do with the case:
                      '%d'%somelongin stance DOES work just fine -- hey, even a *float*
                      instance formats just fine here (it gets truncated). I personally
                      consider this a bug in %d-formatting, definitely NOT in gmpy.


                      Alex

                      Comment

                      • Gabriel Genellina

                        #41
                        Re: Interesting list Validity (True/False)

                        En Fri, 18 May 2007 01:48:29 -0300, Alex Martelli <aleax@mac.come scribió:
                        The gmpy designer, writer and maintainer (all in the singular -- that's
                        me) has NOT chosen anything of the sort. gmpy.mpz does implement
                        __int__ and __long__ -- but '%d'%somempzins tance chooses not to call
                        either of them. sys.maxint has nothing to do with the case:
                        '%d'%somelongin stance DOES work just fine -- hey, even a *float*
                        instance formats just fine here (it gets truncated). I personally
                        consider this a bug in %d-formatting, definitely NOT in gmpy.
                        Yes, sorry, at first I thought it was gmpz which refused to convert itself
                        to long. But the fault is in the string formatting code, and it was
                        pointed out later on this same thread. Floats have the same problem: "%d"
                        % 5.2 does work, but "%d" % 1e30 does not.

                        After digging a bit in the implementation of PyString_Format , for a "%d"
                        format it does:
                        - test if the value to be printed is actually a long integer (using
                        PyLong_Check). Yes? Format as a long integer.
                        - else, convert the value into a plain integer (using PyInt_AsLong), and
                        format that.
                        No attempt is made to *convert* the value to a long integer. I understand
                        that this could be a slow operation, so the various tests should be
                        carefully ordered, but anyway the __long__ conversion should be done.

                        --
                        Gabriel Genellina

                        Comment

                        Working...