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