floating point in 2.0

Alex Martelli aleaxit at yahoo.com
Sun Jun 10 11:38:09 EDT 2001


"Chris Barker" <chrishbarker at home.net> wrote in message
news:3B2120AF.9306D1E3 at home.net...
> You know, after reading all this (I do find it interesting), I wonder
> why I have never seen a language include an easy way to get/compare a
> floating point number in a given precision. One of the first things we
    ...
> if fp1 == fp2 (in the first 5 decimal digits.)
    ...
> Does anyone have any nifty algorithms that they use for this that they
> would like to share? I'd at least like to put them into my own toolbox.

D:\py21>python
Python 2.1 (#15, Apr 16 2001, 18:25:49) [MSC 32 bit (Intel)] on win32
Type "copyright", "credits" or "license" for more information.
Alternative ReadLine 1.4 -- Copyright 2001, Chris Gonnerman
>>> import gmpy
>>> print gmpy.reldiff.__doc__
reldiff(x,y): returns the relative difference between x and y,
where x and y can be any numbers and get coerced to mpf; result is
a non-negative mpf roughly equal to abs(x-y)/((abs(x)+abs(y))/2).

>>> if gmpy.reldiff(0.6,6/10.)<1e-5:
...     print 'ok'
...
ok
>>>

See http:\\gmpy.sourceforce.net.  I slipped behind in the schedule
I had given myself to release a beta for gmpy, but what is missing
is mostly documentation in Python standard form -- latex stuff,
docstrings in the nice first-line/rest-of-it split form, &c -- the code
seems to work pretty solidly, and relative-difference measurement
in particular is useful.  Pretty easy to do for Python floats in a tiny
C extension, if you use that functionality often, e.g.:

::: setup.py:
from distutils.core import setup, Extension
reldif = Extension('reldif', sources=['reldifmodule.c'])
setup (name = "reldif",
       version = "0.1",
       description = "Relative difference of floats",
       author = "Alex Martelli",
       author_email = "aleaxit at yahoo.com",
       ext_modules = [ reldif ]
)
::: reldifmodule.c:
#include "Python.h"
#include <math.h>

static PyObject *
reldif(PyObject *self, PyObject *args)
{
    double x, y, z;
    if (!PyArg_ParseTuple(args, "dd", &x, &y))
        return 0;
    z = fabs(x)+fabs(y);
    if(z) {
        z = 2.0*fabs(x-y)/z;
    }
    return Py_BuildValue("d", z);
}

static PyMethodDef ReldifMethods[] = {
    {"reldif", reldif, METH_VARARGS},
    {0, 0}
};

void
initreldif()
{
    Py_InitModule("reldif", ReldifMethods);
}
:::

You may have to add some -lm on Unix (don't have it
around to try), but that's all you need on Windows:

D:\py21>python setup.py install
running install
running build
running build_ext
building 'reldif' extension
D:\msdev6\VC98\BIN\cl.exe /c /nologo /Ox /MD /W3 /GX -ID:\PYTHON21\Include
/Tcre
ldifmodule.c /Fobuild\temp.win32-2.1\Release\reldifmodule.obj
reldifmodule.c
D:\msdev6\VC98\BIN\link.exe /DLL /nologo /INCREMENTAL:NO
/LIBPATH:D:\PYTHON21\li
bs /EXPORT:initreldif build\temp.win32-2.1\Release\reldifmodule.obj
/OUT:build\l
ib.win32-2.1\reldif.pyd /IMPLIB:build\temp.win32-2.1\Release\reldif.lib
   Creating library build\temp.win32-2.1\Release\reldif.lib and object
build\tem
p.win32-2.1\Release\reldif.exp
running install_lib
copying build\lib.win32-2.1\reldif.pyd -> D:\PYTHON21

Now:
D:\py21>python
Python 2.1 (#15, Apr 16 2001, 18:25:49) [MSC 32 bit (Intel)] on win32
Type "copyright", "credits" or "license" for more information.
Alternative ReadLine 1.4 -- Copyright 2001, Chris Gonnerman
>>> import reldif
>>> reldif.reldif(2/3.0,0.66666)
1.0000050000148979e-005
>>>

You might want to have a "relcmp" that more directly addresses
your concerns, taking x and y (and possibly the tolerance, which
it might default) and returning -1, 0 or 1 like the builtin cmp.  It
might be dangerous (in theory) to have that lying around -- if you
passed it to a list's sort method it might give strange results as
the 'equality' it defines is not transitive... so, I prefer to have the
reldiff only and pay the (small) price of comparing it directly with
the relative-epsilon I need.


Alex






More information about the Python-list mailing list