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