Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Numeric comparison anomaly

0 views
Skip to first unread message

Paul Rubin

unread,
Feb 19, 2003, 7:28:22 AM2/19/03
to
I want to define an "infinite" numeric object, that's greater than
any regular number. I do the obvious (Python 2.2):

>>> class _infinity:
... def __lt__(self, n): return 0
... def __gt__(self, n): return 1
...
>>> infinity = _infinity()
>>> infinity < 9
0
>>> infinity > 99999
1
>>> 99999 < infinity
1

So far so good. But here comes the surprise:

>>> infinity >= 3
0

I wouldn't have predicted this from the description in the docs. It
turns out that since there's no __ge__ method and no __cmp__ method,
the interpreter compared the machine addresses of the infinity object
and the "3" object. The comparison came out one way but could have
come out the other way (or maybe I might have defined "minus infinity"
instead of infinity). It could have been hard to discover this bug by
testing.

Anyway, the right way to implement infinity is with

def __cmp__(self, n): return 1

I only figured all this out after starting to write this post to ask
what was causing the >= anomaly. I decided to post anyway, as a
cautionary tale.

Klaus Alexander Seistrup

unread,
Feb 19, 2003, 8:06:46 AM2/19/03
to
Paul Rubin wrote:

> I want to define an "infinite" numeric object, that's greater than
> any regular number. I do the obvious (Python 2.2):
>
> >>> class _infinity:
> ... def __lt__(self, n): return 0
> ... def __gt__(self, n): return 1
> ...
> >>> infinity = _infinity()
> >>> infinity < 9
> 0
> >>> infinity > 99999
> 1
> >>> 99999 < infinity
> 1
>
> So far so good. But here comes the surprise:
>
> >>> infinity >= 3
> 0

Python has builtin infinity:

#v+

$ python
Python 2.2.2 (#1, Jan 18 2003, 10:18:59)
[GCC 3.2.2 20030109 (Debian prerelease)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
Welcome to rlcompleter2 0.95
for nice experiences hit <tab> multiple times
>>> infinity = float('Inf')


>>> infinity < 9
0
>>> infinity > 99999
1
>>> 99999 < infinity
1

>>> infinity >= 3
1
>>> ^D
$

#v-

You can use "float('-Inf')" and "float('NaN')", too.


// Klaus

--
><> vandag, môre, altyd saam

paul m

unread,
Feb 19, 2003, 8:32:48 AM2/19/03
to

"Klaus Alexander Seistrup" <sp...@magnetic-ink.dk> wrote in message
news:50e6834f-5285-4b01...@news.szn.dk...

>
> Python has builtin infinity:
>
> #v+
>
> $ python
> Python 2.2.2 (#1, Jan 18 2003, 10:18:59)
> [GCC 3.2.2 20030109 (Debian prerelease)] on linux2
> Type "help", "copyright", "credits" or "license" for more information.
> Welcome to rlcompleter2 0.95
> for nice experiences hit <tab> multiple times
> >>> infinity = float('Inf')
> >>> infinity < 9
> 0
> >>> infinity > 99999
> 1
> >>> 99999 < infinity
> 1
> >>> infinity >= 3
> 1
> >>> ^D
> $
>
> #v-
>
> You can use "float('-Inf')" and "float('NaN')", too.
>

Unfortunately, that's entirely platform specific. Neither of the two
platforms I have here at home support float('Inf'), as shown below...

On Win2k:

Python 2.2.1 (#34, Apr 9 2002, 19:34:33) [MSC 32 bit (Intel)] on win32
Type "copyright", "credits" or "license" for more information.
IDLE 0.8 -- press F1 for help


>>> infinity = float('Inf')

Traceback (most recent call last):
File "<pyshell#0>", line 1, in ?


infinity = float('Inf')

ValueError: invalid literal for float(): Inf
>>>

On FreeBSD:

[GCC 2.95.3 20010315 (release) [FreeBSD]] on freebsd4


Type "help", "copyright", "credits" or "license" for more information.

>>> infinity = float('Inf')

Traceback (most recent call last):
File "<stdin>", line 1, in ?
ValueError: invalid literal for float(): Inf
>>>

--Paul

Gerrit Holl

unread,
Feb 19, 2003, 9:28:32 AM2/19/03
to
> > I want to define an "infinite" numeric object, that's greater than
> > any regular number. I do the obvious (Python 2.2):
> >
> > >>> class _infinity:
> > ... def __lt__(self, n): return 0
> > ... def __gt__(self, n): return 1
> > ...
> > >>> infinity = _infinity()
> > >>> infinity < 9
> > 0
> > >>> infinity > 99999
> > 1
> > >>> 99999 < infinity
> > 1
> >
> > So far so good. But here comes the surprise:
> >
> > >>> infinity >= 3
> > 0

You can use the __cmp__ overloader:

21 >>> class A:
21 ... def __cmp__(self, other):
21 ... return 1
21 ...
22 >>> A() > 5
True
23 >>> A() < 9
False
24 >>> A() >= 3
True

See also:
http://www.python.org/dev/doc/devel/ref/customization.html#l2h-97

yours,
Gerrit.

--
Asperger Syndroom - een persoonlijke benadering:
http://people.nl.linux.org/~gerrit/
Het zijn tijden om je zelf met politiek te bemoeien:
http://www.sp.nl/

Klaus Alexander Seistrup

unread,
Feb 19, 2003, 6:55:18 PM2/19/03
to
Paul M wrote:

> Python 2.2.1 (#34, Apr 9 2002, 19:34:33) [MSC 32 bit (Intel)] on win32
> Type "copyright", "credits" or "license" for more information.
> IDLE 0.8 -- press F1 for help
>>>> infinity = float('Inf')
> Traceback (most recent call last):
> File "<pyshell#0>", line 1, in ?
> infinity = float('Inf')
> ValueError: invalid literal for float(): Inf

Hm, too bad.

Piet van Oostrum

unread,
Feb 20, 2003, 5:55:34 AM2/20/03
to
>>>>> Gerrit Holl <ger...@nl.linux.org> (GH) schreef:

GH> You can use the __cmp__ overloader:

GH> 21 >>> class A:
GH> 21 ... def __cmp__(self, other):
GH> 21 ... return 1
GH> 21 ...
GH> 22 >>> A() > 5
GH> True
GH> 23 >>> A() < 9
GH> False
GH> 24 >>> A() >= 3
GH> True

>>> inf = A()
>>> inf > inf
True
>>> inf == inf
False
>>>

--
Piet van Oostrum <pi...@cs.uu.nl>
URL: http://www.cs.uu.nl/~piet [PGP]
Private email: P.van....@hccnet.nl

sism...@hebmex.com

unread,
Feb 20, 2003, 3:38:05 PM2/20/03
to
> From: Piet van Oostrum [mailto:pi...@cs.uu.nl]
> Sent: Thursday, February 20, 2003 4:56 AM

>
> >>>>> Gerrit Holl <ger...@nl.linux.org> (GH) schreef:
>
> GH> You can use the __cmp__ overloader:
>
> GH> 21 >>> class A:
> GH> 21 ... def __cmp__(self, other):
> GH> 21 ... return 1
> GH> 21 ...
> GH> 22 >>> A() > 5
> GH> True
> GH> 23 >>> A() < 9
> GH> False
> GH> 24 >>> A() >= 3
> GH> True
>
> >>> inf = A()
> >>> inf > inf
> True
> >>> inf == inf
> False
> >>>
>

This is correct, or wrong?

-gustavo

Piet van Oostrum

unread,
Feb 20, 2003, 4:13:36 PM2/20/03
to

S> This is correct, or wrong?

I would consider that incorrect. But others may differ. But if it is
considered correct, then > is not an ordering for sets that include inf.
On the other hand, in Python > isn't an ordering in general.

Erik Max Francis

unread,
Feb 20, 2003, 4:26:04 PM2/20/03
to
sism...@hebmex.com wrote:

> > >>> inf = A()
> > >>> inf > inf
> > True
> > >>> inf == inf
> > False
> > >>>
> >
>
> This is correct, or wrong?

Depends on your background and motivation for providing an "infinity"
that compares greater than all numbers. It's easy enought to fix by
doing an isinstance test against the infinity class, and then changing
the behavior however you'd like.

Infinity is not really a number, it's a concept of something greater
than all numbers. Among transfinite cardinals, there are numbers which
represent "infinity" that are greater or less than other "infinities."
Really asking whether infinity equals itself should be indeterminate,
rather than false. Whether that should raise an exception or just
return false values depends on the precise motivation for including
infinities in the first place.

--
Erik Max Francis / m...@alcyone.com / http://www.alcyone.com/max/
__ San Jose, CA, USA / 37 20 N 121 53 W / &tSftDotIotE
/ \ I am a gentlemen: I live by robbing the poor.
\__/ George Bernard Shaw
Blackgirl International / http://www.blackgirl.org/
The Internet resource for black women.

sism...@hebmex.com

unread,
Feb 20, 2003, 4:18:13 PM2/20/03
to
> From: Piet van Oostrum [mailto:pi...@cs.uu.nl]
> Sent: Thursday, February 20, 2003 3:14 PM

>
> >>>>> sism...@hebmex.com (S) wrote:
>
> >> From: Piet van Oostrum [mailto:pi...@cs.uu.nl]
> >> Sent: Thursday, February 20, 2003 4:56 AM
> >>
> >> >>>>> Gerrit Holl <ger...@nl.linux.org> (GH) schreef:
> >>
> GH> You can use the __cmp__ overloader:
> >>
> GH> 21 >>> class A:
> GH> 21 ... def __cmp__(self, other):
> GH> 21 ... return 1
> GH> 21 ...
> GH> 22 >>> A() > 5
> GH> True
> GH> 23 >>> A() < 9
> GH> False
> GH> 24 >>> A() >= 3
> GH> True
> >>
> >> >>> inf = A()
> >> >>> inf > inf
> >> True
> >> >>> inf == inf
> >> False
> >> >>>
> >>
>
> S> This is correct, or wrong?
>
> I would consider that incorrect. But others may differ. But if it is
> considered correct, then > is not an ordering for sets that
> include inf.
> On the other hand, in Python > isn't an ordering in general.
> --

If __cmp__() returns 1, then "inf == inf" can't ever be true,
because __cmp__() is actually saying that it's larger.

-gustavo


Gary Herron

unread,
Feb 20, 2003, 4:30:28 PM2/20/03
to
On Thursday 20 February 2003 12:38 pm, sism...@hebmex.com wrote:
> > From: Piet van Oostrum [mailto:pi...@cs.uu.nl]
> > Sent: Thursday, February 20, 2003 4:56 AM
> >
> > >>>>> Gerrit Holl <ger...@nl.linux.org> (GH) schreef:
> >
> > GH> You can use the __cmp__ overloader:
> >
> > GH> 21 >>> class A:
> > GH> 21 ... def __cmp__(self, other):
> > GH> 21 ... return 1
> > GH> 21 ...
> > GH> 22 >>> A() > 5
> > GH> True
> > GH> 23 >>> A() < 9
> > GH> False
> > GH> 24 >>> A() >= 3
> > GH> True
> >
> > >>> inf = A()
> > >>> inf > inf
> >
> > True
> >
> > >>> inf == inf
> >
> > False
>
> This is correct, or wrong?
>
> -gustavo

This is correct of course. By having __cmp__ return 1 *always*, you
are saying inf is greater than *anything* else without regard to what
the other thing is. (Note that your __cmp__ does not even look at the
second argument.) It will never compare equal to anything (__cmp__
would need to return a zero for that).

Thus

inf > ...any python object...

returns True because __cmp__ returns 1 (meaning "is greater than") and

inf == ...any python object...

returns False because __cmp__ returns 1 (meaning "is greater than" --
not "equal to").


Did you perhaps miss that __cmp__ must return one of three casses:
negative integer: meaning "self is less than other"
0: meaning "self is equal to other"
positive integer: meaning "self is greater than other"


Gary Herron


Piet van Oostrum

unread,
Feb 20, 2003, 4:32:17 PM2/20/03
to
>>>>> sism...@hebmex.com (S) wrote:

S> If __cmp__() returns 1, then "inf == inf" can't ever be true,
S> because __cmp__() is actually saying that it's larger.

Yes, of course, but I mean that I consider this an incorrect
definition of __cmp__.

class A:
def __cmp__(self, other):
return self is not other
would be better.

Gary Herron

unread,
Feb 20, 2003, 4:34:59 PM2/20/03
to


Actually, Python's > *is* an ordering, but he is *not* using
python's > operator. He has redefined it (in a silly fashion)
with the __cmp__ method.

Gary Herron


Paul Rubin

unread,
Feb 20, 2003, 5:22:19 PM2/20/03
to
"Piet van Oostrum" <pi...@cs.uu.nl> writes:

> Yes, of course, but I mean that I consider this an incorrect
> definition of __cmp__.
>
> class A:
> def __cmp__(self, other):
> return self is not other
> would be better.

Hmm, I guess that's an improvement but still leaves an anomaly:

inf1 = A()
inf2 = A()

print (inf1 == inf2)

would then print 0.

Anyway I didn't really need a general infinity. I just wanted a simple
way to write a loop with an optional maximum count:

n = 0
while n <= limit:
if some_test(sequence[n]):
break

Letting limit be infinite was the simplest way of expressing that I
sometimes didn't want to have a limit.

sism...@hebmex.com

unread,
Feb 20, 2003, 5:28:49 PM2/20/03
to
> From: Jim Meyer [mailto:jme...@pdi.com]
> Sent: Thursday, February 20, 2003 4:28 PM
>
> --j, who wonders if 'self.sign = 0' might ever be interesting ...
>

"Neutral infinity"?
It's more "neutral" than anything else.

...must be Swiss.

-gus

Jim Meyer

unread,
Feb 20, 2003, 5:28:29 PM2/20/03
to
Hello!

On Thu, 2003-02-20 at 13:30, Gary Herron wrote:
> > > From: Piet van Oostrum [mailto:pi...@cs.uu.nl]
> > > Sent: Thursday, February 20, 2003 4:56 AM
> > >
> > > >>>>> Gerrit Holl <ger...@nl.linux.org> (GH) schreef:
> > >
> > > GH> You can use the __cmp__ overloader:
> > >
> > > GH> 21 >>> class A:
> > > GH> 21 ... def __cmp__(self, other):
> > > GH> 21 ... return 1
> > > GH> 21 ...
> > > GH> 22 >>> A() > 5
> > > GH> True
> > > GH> 23 >>> A() < 9
> > > GH> False
> > > GH> 24 >>> A() >= 3
> > > GH> True
> > >
> > > >>> inf = A()
> > > >>> inf > inf
> > >
> > > True
> > >
> > > >>> inf == inf
> > >
> > > False

> This is correct of course. By having __cmp__ return 1 *always*, you


> are saying inf is greater than *anything* else without regard to what
> the other thing is. (Note that your __cmp__ does not even look at the
> second argument.) It will never compare equal to anything (__cmp__
> would need to return a zero for that).

While I understand that this is the correct behavior for the above
implementation, I wonder if the implicit question wasn't "Shouldn't
infinity evaluate to be equal to infinity?"

Interestingly, Java considers the cases of both positive and negative
infinity. They are respectively greater than and less than everything
(except themselves); they are equal to themselves only.

Here's a slightly different snippet to break:

class INFINITY:
def __init__(self, type = 1) :
self.sign = cmp(type, 0)
if not self.sign: self.sign = 1
def __cmp__(self, other) :
if isinstance(other, INFINITY) :
return cmp(self.sign, other.sign)
else :
return self.sign

>>> posinf = INFINITY()
>>> neginf = INFINITY(-1)
>>> 1 > neginf
1
>>> 1 < posinf
1
>>> neginf > posinf
0
>>> posinf > neginf
1
>>> posinf > posinf
0
>>> posinf < posinf
0
>>> posinf == posinf
1

You get the idea.

--j, who wonders if 'self.sign = 0' might ever be interesting ...

--
Jim Meyer, Geek at Large jme...@pdi.com


Paul Rubin

unread,
Feb 20, 2003, 6:33:36 PM2/20/03
to
Jim Meyer <jme...@pdi.com> writes:
> While I understand that this is the correct behavior for the above
> implementation, I wonder if the implicit question wasn't "Shouldn't
> infinity evaluate to be equal to infinity?"
>
> Interestingly, Java considers the cases of both positive and negative
> infinity. They are respectively greater than and less than everything
> (except themselves); they are equal to themselves only.

Yeah, my original implementation had signed infinity, but then I
realized I only needed positive infinity, so I took out the sign.
Actually, my *original* original implementation had infinity compare
both larger than everything and smaller than everything. The
application is something like regexps: pat{m,n} means k occurences
of pat, for some m <= k <= n, but both values default to "no limit".
So I wanted to have a single object that I could use as the default
for either m or n. But it turned out to be simpler to just
default m to 0 (I don't have to worry about negative values).

Gary Herron

unread,
Feb 20, 2003, 6:47:38 PM2/20/03
to
> While I understand that this is the correct behavior for the above
> implementation, I wonder if the implicit question wasn't "Shouldn't
> infinity evaluate to be equal to infinity?"


No his question was not about what properties a representation of
infinity *should* have, but rather why his particular object was
exhibiting the behavior he was seeing. Once one understands the
behavior of his "inf", one can attempt to produce a less naive and
more useful representation of infinity which exhibits the desired
behavior.

Gary Herron


Erik Max Francis

unread,
Feb 20, 2003, 9:22:21 PM2/20/03
to
sism...@hebmex.com wrote:

Infinity as a limit needs either to be positive infinity or negative
infinity; if unstated, it's positive infinity. There's no "unsigned
infinity."

--
Erik Max Francis / m...@alcyone.com / http://www.alcyone.com/max/
__ San Jose, CA, USA / 37 20 N 121 53 W / &tSftDotIotE

/ \ Success and failure are equally disastrous.
\__/ Tennessee Williams
Polly Wanna Cracka? / http://www.pollywannacracka.com/
The Internet resource for interracial relationships.

Erik Max Francis

unread,
Feb 20, 2003, 9:24:53 PM2/20/03
to
Jim Meyer wrote:

> While I understand that this is the correct behavior for the above
> implementation, I wonder if the implicit question wasn't "Shouldn't
> infinity evaluate to be equal to infinity?"

The answer really depends on what you're using the infinities for. In
transfinite cardinals, you can easily talk about "an infinity" that is
larger than "another infinity."

In limit theory, "infinity" just means "the limit does not exist in that
the value increases (or decreases) without bound." Infinity isn't a
number, so talking about it equally another infinity is getting into a
problem zone.

Paul Rubin

unread,
Feb 20, 2003, 10:01:15 PM2/20/03
to
Erik Max Francis <m...@alcyone.com> writes:
> Infinity as a limit needs either to be positive infinity or negative
> infinity; if unstated, it's positive infinity. There's no "unsigned
> infinity."

IEEE 754 supports unsigned (projective) infinity. This is useful for
complex arithmetic, among other things. The extended complex numbers
include projective infinity. There's no positive or negative
infinity.

Tim Peters

unread,
Feb 20, 2003, 10:23:30 PM2/20/03
to
[Erik Max Francis]

> Infinity as a limit needs either to be positive infinity or negative
> infinity; if unstated, it's positive infinity. There's no "unsigned
> infinity."

There can be. google on

infinity affine projective 754

for recent history about this choice in relation to computer arithmetic.
The Intel 8087 floating-point coprocessor actually had a hardware flag to
choose between affine (two signed infinities) and projective (one signless
infinity) modes of operation. Before its final draft, 754 switched from
specifying that projective mode was the default to dropping projective mode
altogether. This was a contentious decision at the time. Python still
ignores the issue entirely <wink>.


Steven Taschuk

unread,
Feb 21, 2003, 1:00:08 AM2/21/03
to
Quoth Jim Meyer:
[...]

> Here's a slightly different snippet to break:
>
> class INFINITY:
> def __init__(self, type = 1) :
> self.sign = cmp(type, 0)
> if not self.sign: self.sign = 1
> def __cmp__(self, other) :
> if isinstance(other, INFINITY) :
> return cmp(self.sign, other.sign)
> else :
> return self.sign
[...]

> --j, who wonders if 'self.sign = 0' might ever be interesting ...

If I've understood your code correctly, with self.sign == 0 we'd
have
-inf < 0inf < +inf
and 0inf would compare as equal to all other objects (at least
when it was on the left-hand side of the comparison).

In a sense, then, 0inf means "an arbitrary finite number". Using
"INFINITY(0) == x" to test "x is finite" is a little odd, but the
test itself is useful. (It looks (very slightly) more sensible as
"INFINITY(False) == x".)

--
Steven Taschuk stas...@telusplanet.net
"What I find most baffling about that song is that it was not a hit."
-- Tony Dylan Davis (CKUA)

Steven Taschuk

unread,
Feb 21, 2003, 12:58:15 AM2/21/03
to
Quoth Erik Max Francis:
[...]

> Infinity as a limit needs either to be positive infinity or negative
> infinity; if unstated, it's positive infinity. There's no "unsigned
> infinity."

There are uses for algebras on R U {oo}, that is, the real numbers
augmented with a single unsigned infinity. Gosper refers to such
an algebra in his algorithms for continued fraction arithmetic,
for example.

If memory serves, the similar C U {oo}, i.e., the complex plane
augmented with a single "point at infinity", finds use in complex
analysis. I think that set even has a name, but I'm damned if I
can remember it.

However, I don't know of a case in which having separate -oo, +oo
and oo all at once is useful. The closest thing I can think of is
allowing the value 0/0 in rational arithmetic, but that's better
conceived of as a NaN than as an infinity.

--
Steven Taschuk stas...@telusplanet.net
Every public frenzy produces legislation purporting to address it.
(Kinsley's Law)

Gonçalo Rodrigues

unread,
Feb 21, 2003, 9:48:35 AM2/21/03
to
On Thu, 20 Feb 2003 22:58:15 -0700, Steven Taschuk
<stas...@telusplanet.net> wrote:

>Quoth Erik Max Francis:
> [...]
>> Infinity as a limit needs either to be positive infinity or negative
>> infinity; if unstated, it's positive infinity. There's no "unsigned
>> infinity."
>
>There are uses for algebras on R U {oo}, that is, the real numbers
>augmented with a single unsigned infinity. Gosper refers to such
>an algebra in his algorithms for continued fraction arithmetic,
>for example.
>

You can viw this as the circle S^1.

>If memory serves, the similar C U {oo}, i.e., the complex plane
>augmented with a single "point at infinity", finds use in complex
>analysis. I think that set even has a name, but I'm damned if I
>can remember it.
>

It's the Riemman Sphere by golly. The infinity is the north pole. You
can also view it as the projective space of lines in R^2. Or...

>However, I don't know of a case in which having separate -oo, +oo
>and oo all at once is useful. The closest thing I can think of is
>allowing the value 0/0 in rational arithmetic, but that's better
>conceived of as a NaN than as an infinity.

There are inumerous cases where adding a point of infinity is essential.
It is the simplest method of compactifying a space. And now that I am
studying Thom Spectra, it is also one of the essential tricks in the
Thom construction. The list goes on.

Uh..., wait... this is a Python newsgroup right? *crawls away*

With my best regards,
G. Rodrigues

Piet van Oostrum

unread,
Feb 22, 2003, 12:08:51 PM2/22/03
to
>>>>> Gary Herron <ghe...@islandtraining.com> (GH) wrote:

GH> Actually, Python's > *is* an ordering, but he is *not* using
GH> python's > operator. He has redefined it (in a silly fashion)
GH> with the __cmp__ method.

What I meant is that, if you use '>', you usually expect it to have the
properties of an ordering. That implementation did not have that property.
Most people probably even expect it to be a total ordering.
And nom Python's > is *not* an ordering, at least not for general objects.
It is possible to have a > b > a for certain objects a and b.

0 new messages