RE: [Python-Dev] Why aren't more things weak referencable

"Martin v. Löwis" wrote:
Never rule out "foolish" consistencies. I can imagine a system where multiple, heterogeneous values all get run through a weakref processor; to have string objects pass through without Yet Another try/except would be a design and maintenance boon. Quite similar to my current "pet peeve":
...writing an O-R mapper, this particular hobgoblin bites me rather often ;) Robert Brewer MIS Amor Ministries fumanchu@amor.org

On Mon, May 31, 2004, Robert Brewer wrote:
Time for you to bite the bullet. Guido has all-but-decreed that the future of comparisons is that TypeError will be raised for all operators other than == and <> for types that have no appropriate relationship system. -- Aahz (aahz@pythoncraft.com) <*> http://www.pythoncraft.com/ "as long as we like the same operating system, things are cool." --piranha

When that happens, I hope that comparisons between long and float will either raise TypeError or behave as if they are done in infinite precision. Right now, the long gets converted to float, which may lose precision; as a result, it is possible to have values such that a==b, b==c, and a!=c.

I agree that doing them as if usin infinite precision is best, but I adamantly oppose the idea that they should not be comparable at all. To the contrary, we should do our best to ensure that int/long are properly and cleanly embedded in floats. That's why I introduced the change to int/long division after all. --Guido van Rossum (home page: http://www.python.org/~guido/)

I agree that doing them as if usin infinite precision is best, but I adamantly oppose the idea that they should not be comparable at all.
As do I.
Agreed. Unfortunately, long/float comparison doesn't work quite correctly right now:
One strategy for solving the problem is to observe that for every floating-point implementation, there is a number N with the property that if x >= N, converting x from float to long preserves information, and if x <= N, converting x from long to float preserves information. Therefore, instead of unconditionally converting to float, the conversion's direction should be based on the value of one of the comparands. Of course, such comparisons can be made faster by doing a rough range check first, and doing the actual conversion only if the number of bits in the long is commensurate with the exponent of the float.

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? --Guido van Rossum (home page: http://www.python.org/~guido/)

Can't you do it like so: def cmp_long_vs_float(l, f): try: lf = float(l) except OverflowError: if special_float_value(f): # NaN, Inf return cmp(0.0, f) return cmp(l, 0L) else: return cmp(lf, f) The try/else control flow seems to be what Python does today. If the OverflowError is triggered, then the magnitude of l is bigger than any finite float so you might just as well compare it against 0L. Infinite floats are handled by the "if special_float_value(f):" branch, or just ignored if you prefer.. (but having 2L**2000 compare greater than +INF would bring complaints) If it turns out to be more efficient, the implementation could LBYL to see whether l can convert to float without overflow. Jeff

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)

On Mon, May 31, 2004, Robert Brewer wrote:
Time for you to bite the bullet. Guido has all-but-decreed that the future of comparisons is that TypeError will be raised for all operators other than == and <> for types that have no appropriate relationship system. -- Aahz (aahz@pythoncraft.com) <*> http://www.pythoncraft.com/ "as long as we like the same operating system, things are cool." --piranha

When that happens, I hope that comparisons between long and float will either raise TypeError or behave as if they are done in infinite precision. Right now, the long gets converted to float, which may lose precision; as a result, it is possible to have values such that a==b, b==c, and a!=c.

I agree that doing them as if usin infinite precision is best, but I adamantly oppose the idea that they should not be comparable at all. To the contrary, we should do our best to ensure that int/long are properly and cleanly embedded in floats. That's why I introduced the change to int/long division after all. --Guido van Rossum (home page: http://www.python.org/~guido/)

I agree that doing them as if usin infinite precision is best, but I adamantly oppose the idea that they should not be comparable at all.
As do I.
Agreed. Unfortunately, long/float comparison doesn't work quite correctly right now:
One strategy for solving the problem is to observe that for every floating-point implementation, there is a number N with the property that if x >= N, converting x from float to long preserves information, and if x <= N, converting x from long to float preserves information. Therefore, instead of unconditionally converting to float, the conversion's direction should be based on the value of one of the comparands. Of course, such comparisons can be made faster by doing a rough range check first, and doing the actual conversion only if the number of bits in the long is commensurate with the exponent of the float.

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? --Guido van Rossum (home page: http://www.python.org/~guido/)

Can't you do it like so: def cmp_long_vs_float(l, f): try: lf = float(l) except OverflowError: if special_float_value(f): # NaN, Inf return cmp(0.0, f) return cmp(l, 0L) else: return cmp(lf, f) The try/else control flow seems to be what Python does today. If the OverflowError is triggered, then the magnitude of l is bigger than any finite float so you might just as well compare it against 0L. Infinite floats are handled by the "if special_float_value(f):" branch, or just ignored if you prefer.. (but having 2L**2000 compare greater than +INF would bring complaints) If it turns out to be more efficient, the implementation could LBYL to see whether l can convert to float without overflow. Jeff

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)
participants (5)
-
Aahz
-
Andrew Koenig
-
Guido van Rossum
-
Jeff Epler
-
Robert Brewer