[Python-Dev] Comparing heterogeneous types
Andrew Koenig
ark-mlist at att.net
Thu Jun 3 11:16:42 EDT 2004
> Do you think you can come up with a patch, or at least a description
> of an algorithm that someone without a wizard level understanding of
> the issues could implement?
The following code is lightly but not exhaustively tested, but I do think it
gives a good idea of the algorithm. In particular, note that
compare(fmagic, lmagic+1) is -1 even though (fmagic==lmagic+1) yields True.
lmagic = 1
fmagic = 1.0
while fmagic + 1.0 != fmagic:
fmagic += fmagic
lmagic += lmagic
assert fmagic + 1.0 == fmagic
assert fmagic - 1.0 != fmagic
# fmagic and lmagic are the float and long representations of the
# smallest power of 2 for which the floating-point LSB is strictly
# greater than 1. Accordingly, adding 1 to this magic value doesn't
# change it, but subtracting 1 does (because it is a power of 2, so
# the subtraction makes the representation one bit shorter).
# Because of the properties of fmagic and lmagic, converting an
# integer that is < lmagic to floating-point will lose no information,
# and converting a floating-point number that is >= fmagic to long
# will also lose no information.
def sign(x):
if x > 0:
return 1
if x < 0:
return -1
return 0
def simple_compare(x, y): # arguments both float or neither
if x < y:
return -1
if x > y:
return 1
return 0
def compare(x, y):
# We handle only integers and floats
if type(x) not in [int, long, float]:
raise TypeError, "left argument to compare not integer or float"
if type(y) not in [int, long, float]:
raise TypeError, "right argument to compare not integer or float"
# If the arguments are the same type (counting int and long as
# the same), there's nothing special to do
if (type(x) == float) == (type(y) == float):
return simple_compare(x, y)
# Perhaps the signs will make the comparison unnecessary
signx = sign(x)
signy = sign(y)
if signx != signy or signx == 0:
return simple_compare(signx, signy)
# Now we know that both arguments are nonzero and have the same
# sign. We'll use signx to remember the original sign and make
# the arguments both positive for convenience.
if signx < 0:
x = -x
y = -y
# We have reduced the problem to one where the arguments are both
# positive and exactly one of them is float--but we don't know
# which one. For convenience, we'll make x float by swapping x
# and y if necessary, adjusting signx as appropriate.
if type(y) == float:
x, y = y, x
signx = -signx
assert type(x) == float
assert type(y) in [int, long]
assert x > 0 and y > 0
# If x and y are on different sides of the magic barrier, we're
# done.
if x >= fmagic and y < lmagic:
return signx
if x < fmagic and y >= lmagic:
return -signx
# Now we know that x and y are on the same side of the barrier.
# Depending on which side, we will convert x to long or y to
# float, then compare.
if x >= fmagic:
x = long(x)
else:
y = float(y)
return signx * simple_compare(x, y)
More information about the Python-Dev
mailing list