FixedPoint
Michael Amrhein
michael.amrhein at t-online.de
Thu Feb 7 12:40:00 EST 2002
"Mark McEahern" <mark at mceahern.com> schrieb im Newsbeitrag
news:mailman.1013070672.23308.python-list at python.org...
> In the FixedPoint module found here:
>
>
>
ftp://ftp.python.org/pub/python/contrib-09-Dec-1999/DataStructures/FixedPoin
> t.py.Z
>
> there seems to be a bug comparing to None like this:
>
> if f == None:
>
> Demo:
>
> $ python
> Python 2.2 (#1, Dec 31 2001, 15:21:18)
> [GCC 2.95.3-5 (cygwin special)] on cygwin
> Type "help", "copyright", "credits" or "license" for more information.
> >>> import FixedPoint
> >>> f = FixedPoint.FixedPoint(1.0)
> >>> if f == None:
> ... print "that's not true!"
> ...
> Traceback (most recent call last):
> File "<stdin>", line 1, in ?
> File "FixedPoint.py", line 272, in __cmp__
> xn, yn, p = _norm(self, other)
> File "FixedPoint.py", line 415, in _norm
> y = FixedPoint(y, x.p)
> File "FixedPoint.py", line 216, in __init__
> raise TypeError("can't convert to FixedPoint: " + `value`)
> TypeError: can't convert to FixedPoint: None
>
> This doesn't happen if you use either of the following:
>
> if f is None:
> ...
>
> if not f:
> ...
>
> I ran into this because PyPgSql (v2.0) uses the first method:
>
> File "/usr/lib/python2.2/site-packages/pyPgSQL/PgSQL.py", line 1434,
in
> _quote
>
> if value == None:
>
> I'm not sure what the best fix is here but one that works is to modify the
> __cmp__ method for FixedPoint to anticipate comparison to None. Here's
the
> current __cmp__:
>
> def __cmp__(self, other):
> xn, yn, p = _norm(self, other)
> return cmp(xn, yn)
>
> The fix would look like this:
>
> def __cmp__(self, other):
> ## To avoid crashing on if x == None and the like:
> if other is None:
> return 1
> xn, yn, p = _norm(self, other)
> return cmp(xn, yn)
>
> Or perhaps it'd be better to muck with __eq__ and __ne__? Well, anyway,
> that mod to __cmp__ works.
>
> Cheers,
>
> // mark
>
Hi Mark,
your patch fixes the problem and makes FixedPoint more compatible with the
built-in numeric types.
However, as a hint to the author(s) of PyPgSQL: it's always more safe to use
'if x is None' to test if x is None ;-)
There is another bug in FixedPoint:
>>> FixedPoint(3, 0) / FixedPoint(2, 0)
FixedPoint('2.', 0)
>>> FixedPoint(5, 0) / FixedPoint(2, 0)
FixedPoint('2.', 0)
This is due to a bug in the helper routine _roundquotient.
A fixed and more general (negative quotient) version would look like this:
def _roundquotient(x, y):
i, r = divmod(x, y)
c = cmp(abs(2*r), abs(y))
# r > y/2 or r = y/2 and i not negative:
if c > 0 or (c == 0 and i >= 0):
return i + 1
else:
return i
Note that this will break the test routine because there's a corresponding
error.
You will have to change
assert o == fp(".998", 10)
into
assert o == fp(".999", 10)
two times.
Cheers,
Michael
P.S.: I've written a simular class named 'fixed' with portions adopted from
Tim's FixedPoint, but a slightly different constructor (no default
precision; precision calculated from given value, if no precision given) and
some additional functions. I'll post it in response to your original
request.
More information about the Python-list
mailing list