Python speed vs csharp

Bengt Richter bokr at oz.net
Fri Aug 1 10:05:36 EDT 2003


On 1 Aug 2003 03:11:35 GMT, bokr at oz.net (Bengt Richter) wrote:
[...]
>    # inlining code from old version:
>    # constant assignments hoisted out of loop, of course
>    p  =  0.3275911
>    a1 =  0.254829592
>    a2 = -0.284496736
>    a3 =  1.421413741
>    a4 = -1.453152027
>    a5 =  1.061405429
>    x = 1.2345
>    for i in xrange(100000):
>        t = 1.0 / (1.0 + p*float(x))
>        erfcx = ( (a1 + (a2 + (a3 +
>                  (a4 + a5*t)*t)*t)*t)*t ) * math.exp(-(x**2))
>    t4 = clock()     
>    for i in xrange(100000): erfc_in_c(1.2345)
>    t5=clock()
>    print 'old: %f, new: %f, inline: %f, in_c %f' %(t2-t1, t3-t2, t4-t3, t5-t4)

D'oh ...

    # inlining the new version code
    p  =  0.3275911
    a1 =  0.254829592
    a2 = -0.284496736
    a3 =  1.421413741
    a4 = -1.453152027
    a5 =  1.061405429
    exp = math.exp
    for i in xrange(100000):
        t = 1.0 / (1.0 + p*x) #XXX# don't need float(), since p is float
        erfcx = ( (a1 + (a2 + (a3 +
                  (a4 + a5*t)*t)*t)*t)*t ) * exp(-x**2) #XXX# elim attr lookup on global math.exp
    t6=clock()
    print 'old: %f, new: %f, inline: %f, in_c %f, inline new %f' %(
            t2-t1, t3-t2, t4-t3, t5-t4, t6-t5)


>=======================================================================
>
>Result is:
>
>
>[19:48] C:\pywk\cstuff>erfcopt.py
>old: 4.490975, new: 3.123005, inline: 3.051674, in_c 0.806907
>
>I was surprised that the inline gain was not more, but I guess there was enough computation
>to obscure that cost. Anyway, moving some of the work to def-time paid off about 30%. But
>going to C cut 82%.
>

[ 6:48] C:\pywk\cstuff>erfcopt.py
old: 4.448979, new: 3.112778, inline: 3.073672, in_c 0.806066, inline new 2.193491

Ok, that last number is a bit more like it. Of course the C version is still the fastest.
Forgot to include the source ;-/ If you have MSVC++6 and python sources you can compile
 and link the following with your version of this .cmd file:

====< mkpydll.cmd >===========================================
@cl -LD -nologo -Id:\python22\include %1.c -link -LIBPATH:D:\python22\libs -export:init%1
==============================================================
Invoked thus:

[ 7:03] C:\pywk\cstuff>mkpydll erfc
erfc.c
   Creating library erfc.lib and object erfc.exp


(Tested only as far as you've seen in recent posts!)
====< erfc.c >================================================
/*
** erfc.c taken with slight mod from Mike @ nospam.com's c# posted version of
** Rational approximation for erfc(x) (Abramowitz & Stegun, Sec. 7.1.26)
** Fifth order approximation. |error| <= 1.5e-7 for all x
** Version 0.01 20030731 Bengt Richter bokr at oz.net
*/

#include <math.h>
static double
erfc( double x )
{
   double p, a1, a2, a3, a4, a5;
   double t, erfcx;

   p  =  0.3275911;
   a1 =  0.254829592;
   a2 = -0.284496736;
   a3 =  1.421413741;
   a4 = -1.453152027;
   a5 =  1.061405429;

   t = 1.0 / (1.0 + p*x);
   erfcx = ( (a1 + (a2 + (a3 +
             (a4 + a5*t)*t)*t)*t)*t ) * exp(-pow(x,2.0));
   return erfcx;
}

#include "Python.h"
#include <windows.h>

static char doc_erfc[] =
    "erfc(x) -> approximation\n";

static PyObject *
erfc_erfc(PyObject *self, PyObject *args)
{
    PyObject *rv;
    double farg;
    
    if (!PyArg_ParseTuple(args, "d:erfc", &farg)) /* Single floatingpoint arg */
        return NULL;
    rv = Py_BuildValue("d", erfc(farg));
    return rv;
}

/* List of functions defined in the module */
static struct PyMethodDef erfc_module_methods[] = {
    {"erfc", erfc_erfc, METH_VARARGS, doc_erfc},
    {NULL, NULL}                 /* sentinel */
};


/* Initialization function for the module (*must* be called initerfc) */
static char doc_erfc_module[] = 
    "# Rational approximation for erfc(x) (Abramowitz & Stegun, Sec. 7.1.26)\n"
    "# Fifth order approximation. |error| <= 1.5e-7 for all x\n";

DL_EXPORT(void)
initerfc(void)
{
    PyObject *m, *d, *x;

    /* Create the module and add the functions */
    m = Py_InitModule("erfc", erfc_module_methods);
    d = PyModule_GetDict(m);
    x = PyString_FromString(doc_erfc_module);
    PyDict_SetItemString(d, "__doc__", x);
    Py_XDECREF(x);
}
==============================================================
>>> help('erfc')
Help on module erfc:

NAME
    erfc

FILE
    c:\pywk\cstuff\erfc.dll

DESCRIPTION
    # Rational approximation for erfc(x) (Abramowitz & Stegun, Sec. 7.1.26)
    # Fifth order approximation. |error| <= 1.5e-7 for all x

FUNCTIONS
    erfc(...)
        erfc(x) -> approximation

DATA
    __file__ = 'erfc.dll'
    __name__ = 'erfc'


>>> from erfc import erfc
>>> for x in range(10): print '%s => %g'%(x,erfc(x))
...
0 => 1
1 => 0.157299
2 => 0.00467786
3 => 2.21051e-005
4 => 1.54603e-008
5 => 1.54782e-012
6 => 2.17852e-017
7 => 4.26424e-023
8 => 1.15275e-029
9 => 4.28336e-037

Regards,
Bengt Richter




More information about the Python-list mailing list