Re: C is it faster than numpy

Michael <[email protected]> Sat, 26 Feb 2022 01:33:55 +0000
Newsgroups gmane.comp.python.org.uk
Message-ID <CAB+QZVBu0nfiQ39Zf_cftO7hYJfsHK3hYNqhYz4=TPzFAPoiiw@mail.gmail.com>
--===============8837496801027313951==
Content-Type: multipart/alternative; boundary="0000000000009cf95105d8e1cf23"

--0000000000009cf95105d8e1cf23
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

Hi,

On Fri, 25 Feb 2022 at 16:22, BELAHCENE Abdelkader <
[email protected]> wrote:

> Hi,
> What do you mean?
> the python and C programs are not equivalent?
>
>
The python and C programs are NOT equivalent. (surface level they are: they
both calculate the triangular number of N, N times, inefficiently and
slowly, but the way they do it is radically different)

Let's specifically compare the num.py and the C versions. The pure python
version *should* always be slower, so it's irrelevant here. (NB, I show a
version below where the pure python version is quicker than both :-) )

The num.py version:

* It creates an array containing the numbers 1 to n. It then call's
num.py's sum function with that array n times.

The C version :
* Calls a function n times. That function has a tight loop using a long
that sums all the numbers from 1 to n.

These are *very* different operations. The former can be vectorised, and
while I don't use num.py, and while I'm not a betting person I would bet a
Mars bar that the num.py version will throw the array at a SIMD
implementation. A cursory look at the source to numpy does indeed show that
this is the case (fx: grabs a mars bar :) ), and not only that it's
optimised for a wide variety of CPU architectures.
https://github.com/numpy/numpy/tree/main/numpy/core/src/common/simd

If you don't know what that means, take a look at this --
https://en.wikipedia.org/wiki/Streaming_SIMD_Extensions numpy however
supports multiple versions of SIMD - including things like this:
https://en.wikipedia.org/wiki/AVX-512 - which is pretty neat.

Upshot - numpy will /essentially/ just throw the entire array at the CPU
and say "add these, give me the result". And it'll be done. (OK there's a
bit more to it, but that's the principle)

By contrast your naive C version has to repeatedly create stack frames,
push arguments onto it, pop arguments allocate memory on the stack, etc.
It's also single threaded, and has no means of telling the CPU "add all
these together, and I don't care how", so it literally is one after the
other. The actual work it's doing to get the same answer is simply much
greater and many many more clock cycles.

If you took the same approach as numpy it's *possible* you *might* get
something similarly fast. (But you'd have a steep learning curve and you'd
likely only optimise for one architecture...)

Aside: What size is the *value*  the C version is creating? Well it's just
(n * n+1 ) /2  - primary school triangular number stuff. So 50K
is 1250025000 - which is a 31 bit number. So the C version will fail on a
32 bit machine as soon as you try over 65536 as the argument... (On a
64bit machine admittedly the fall over number is admittedly higher... :-) )

C and C++ *are* faster than pure python. That's pretty much always going to
be the case ( *except* for a specialising python compiler that compiles a
subset of python to either C/C++/Rust or assembler). However, python +
highly optimised C/C++/etc libraries will likely outperform naive C/C++
code - as you've ably demonstrated here.

Why? Because while on the surface the two programs are vaguely similar -
calculate the triangular number of N, N times.  In practice, the way that
they do it is so different, you get dramatically different results.

As a bonus - you can get faster than both your num.py and C versions with
pure python, by several orders of magnitude. You can then squeeze out a few
more percent out of it.  Output from a pure python version of a piece of
code that performs the same operation - calculates the triangle number of
N, N times:

michael@conceptual:~$ ./triangles.py 15000000
time using pure python: 1.81 sec
time using pure python & memoisation: 1.7 sec

Note that's 15 million, not 50,000 - and it took the same time for my
machine (recent core i7) as numpy did for you on your machine for just
50,000. That's not because I have a faster machine (I expect I don't).

What's different? Well the pure python version is this - it recognises you
were calculating  the triangular number for N and just calculates that
instead :-)

def normaltriangle(n):
   return (n*(n+1))/2
... called like this ..
   tm1=3Dit.timeit(stmt=3Dlambda: normaltriangle(count), number=3Dcount)
   print(f"time using pure python: {round(tm1,2)} sec")

The (naive) memoisation version is this:

def memoise(f):
   cache =3D {}
   def g(n):
       if n in cache:
           return cache[n]
       else:
           X =3D f(n)
           cache[n] =3D X
           return X
   return g

@memoise
def triangle(n):
   return (n*(n+1))/2

... called like this ...
   tm2=3Dit.timeit(stmt=3Dlambda: triangle(count), number=3Dcount)
   print(f"time using pure python & memoisation: {round(tm2,2)} sec")


Original file containing both:

#!/usr/bin/python3

import timeit as it

def memoise(f):
   cache =3D {}
   def g(n):
       if n in cache:
           return cache[n]
       else:
           X =3D f(n)
           cache[n] =3D X
           return X
   return g

@memoise
def triangle(n):
   return (n*(n+1))/2


def normaltriangle(n):
   return (n*(n+1))/2


if __name__ =3D=3D "__main__":
   import sys
   count =3D int(sys.argv[1])
   tm1=3Dit.timeit(stmt=3Dlambda: normaltriangle(count), number=3Dcount)
   print(f"time using pure python: {round(tm1,2)} sec")

   tm2=3Dit.timeit(stmt=3Dlambda: triangle(count), number=3Dcount)
   print(f"time using pure python & memoisation: {round(tm2,2)} sec")

I guess the point here is this: focussing on the language/tool C vs python
ignores how "well" the C code is written and how "well" the python code is
written.

However worrying about *that* rather than "is there a smarter way of doing
this" means you can sometimes miss the 300 fold speed up (vs numpy) or 6000
fold speed up (vs your python). I must admit as well, I was a little
surprised that the memoised version worked even this well with such simple
code.

But the point is when comparing C to numpy, you're really comparing *your*
C with *numpy's* C code, and as you can see from their code, your repeated
calls are very different from a vectorised call to CPU processor extensions
designed specifically for this sort of work...

Gets even sillier (in a fun way :) ) if you can throw the code at several
hundred GPU cores...

Hope this was vaguely interesting...


Michael.


On Fri, 25 Feb 2022 at 16:22, BELAHCENE Abdelkader <
[email protected]> wrote:

> Hi,
> What do you mean?
> the python and C programs are not equivalent?
>
>
> Le ven. 25 f=C3=A9vr. 2022 =C3=A0 10:42, Giorgio Zoppi <giorgio.zoppi@gma=
il.com> a
> =C3=A9crit :
>
>> Well,
>> numpy is written in C :) Maybe your C is not the numpy equivalent?
>> Best Regards,
>> Giorgio
>>
>> Il giorno ven 25 feb 2022 alle ore 09:03 BELAHCENE Abdelkader <
>> [email protected]> ha scritto:
>>
>>> Hi,
>>> a lot of people think that C (or C++) is faster than python, yes I
>>> agree, but I think that's not the case with numpy, I believe numpy is
>>> faster than C, at least in some cases.
>>>
>>>
>>> *Is there another explanation ?Or where can find  a doc speaking  about
>>> the subject?*Thanks a lot
>>> Regards
>>> Numpy implements vectorization for arrays, or I'm wrong. Anyway here is
>>> an example Let's look at the following case:
>>> Here is the result on my laptop i3:
>>>
>>> Labs$ *python3 tempsExe.py  50000*
>>>   sum with Python: 1250025000 and NumPy 1250025000
>>>       time used Python Sum: * 37.28 sec *
>>>       time used  Numpy Sum:  *1.85 sec*
>>>
>>> Labs$ *./tt    50000 *
>>>
>>>
>>> *   CPU  time :7.521730    The value : 1250025000 *
>>> --------------------------------------------
>>>
>>> This is the Python3 program :
>>>
>>> import timeit as it
>>> import numpy as np
>>> import sys
>>> try :
>>> n=3Deval(sys.argv[1])
>>> except:
>>> print ("needs integer as argument") ; exit()
>>>
>>> a=3Drange(1,n+1)
>>> b=3Dnp.array(a)
>>> def func1():     return sum(a)
>>> def func2(): return np.sum(b)
>>>
>>> print(f"sum with Python: {func1()} and NumPy {func2()} ")
>>> tm1=3Dit.timeit(stmt=3Dfunc1, number=3Dn)
>>> print(f"time used Python Sum: {round(tm1,2)} sec")
>>> tm2=3Dit.timeit(stmt=3Dfunc2, number=3Dn)
>>> print(f"time used  Numpy Sum: {round(tm2,2)} sec")
>>>
>>> and Here the C program:
>>> #include <time.h>
>>> #include <stdio.h>
>>> #include <stdlib.h>
>>> long func1(int n){
>>>          long  r=3D0;
>>>         for (int  i=3D1; i<=3D n;i++) r+=3D i;
>>>          return r;
>>> }
>>> int main(int argc, char* argv[]){
>>>          clock_t c0, c1;
>>>         long v,count; int n;
>>>        if ( argc < 2) {
>>>               printf("Please give an argument");
>>>              return -1;
>>>       }
>>>     n=3Datoi(argv[1]);
>>>     c0 =3D clock();
>>>      *for (int j=3D0;j < n;j++) v=3Dfunc1(n);*
>>>      c1 =3D clock();
>>>      printf ("\tCPU  time :%.2f sec", (float)(c1 - c0)/CLOCKS_PER_SEC);
>>>      printf("\n\tThe value : %ld\n",  v);
>>> }
>>> _______________________________________________
>>> python-uk mailing list
>>> [email protected]
>>> https://mail.python.org/mailman/listinfo/python-uk
>>>
>>
>>
>> --
>> Life is a chess game - Anonymous.
>> _______________________________________________
>> python-uk mailing list
>> [email protected]
>> https://mail.python.org/mailman/listinfo/python-uk
>>
> _______________________________________________
> python-uk mailing list
> [email protected]
> https://mail.python.org/mailman/listinfo/python-uk
>

--0000000000009cf95105d8e1cf23
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div dir=3D"ltr">Hi,<div><br></div><div><div dir=3D"ltr" c=
lass=3D"gmail_attr">On Fri, 25 Feb 2022 at 16:22, BELAHCENE Abdelkader &lt;=
<a href=3D"mailto:[email protected]">[email protected]=
z</a>&gt; wrote:<br></div><blockquote class=3D"gmail_quote" style=3D"margin=
:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"=
><div dir=3D"ltr"><div>Hi,</div><div>What do you mean?</div><div>the python=
 and C programs are not equivalent?</div><div><br></div></div></blockquote>=
</div><div><br></div><div>The python and C programs are NOT equivalent. (su=
rface level they are: they both calculate the triangular number of N, N tim=
es, inefficiently and slowly, but the way they do it is radically different=
)</div><div><br></div><div>Let&#39;s specifically compare the num.py and th=
e C versions. The pure python version *should* always be slower, so it&#39;=
s irrelevant here. (NB, I show a version below where the pure python versio=
n is quicker than both :-) )</div><div><br></div><div>The num.py version:</=
div><div><br></div><div>* It creates an array containing the numbers 1 to n=
. It then call&#39;s num.py&#39;s sum function with that array n times.<br>=
</div><div><br></div><div>The C version :</div><div>* Calls a function n ti=
mes. That function has a tight loop using a long that sums all the numbers =
from 1 to n.</div><div><br></div><div>These are *very* different operations=
. The former can be vectorised, and while I don&#39;t use num.py, and while=
 I&#39;m not a betting person I would bet a Mars bar that the num.py versio=
n will throw the array at a SIMD implementation. A cursory look at the sour=
ce to numpy does indeed show that this is the case (fx: grabs a mars bar :)=
 ), and not only that it&#39;s optimised for a wide variety of CPU architec=
tures.=C2=A0 <a href=3D"https://github.com/numpy/numpy/tree/main/numpy/core=
/src/common/simd">https://github.com/numpy/numpy/tree/main/numpy/core/src/c=
ommon/simd</a></div><div><br></div><div>If you don&#39;t know what that mea=
ns, take a look at this --=C2=A0<a href=3D"https://en.wikipedia.org/wiki/St=
reaming_SIMD_Extensions">https://en.wikipedia.org/wiki/Streaming_SIMD_Exten=
sions</a>=C2=A0numpy however supports multiple versions of SIMD - including=
 things like this:=C2=A0<a href=3D"https://en.wikipedia.org/wiki/AVX-512">h=
ttps://en.wikipedia.org/wiki/AVX-512</a> - which is pretty neat.</div><div>=
<br></div><div>Upshot - numpy will /essentially/ just throw the entire arra=
y at the CPU and say &quot;add these, give me the result&quot;. And it&#39;=
ll be done. (OK there&#39;s a bit more to it, but that&#39;s the principle)=
</div><div><br></div><div>By contrast your naive C version has to repeatedl=
y create stack frames, push arguments onto it, pop arguments allocate memor=
y on the stack, etc. It&#39;s also single threaded, and has no means of tel=
ling the CPU &quot;add all these together, and I don&#39;t care how&quot;, =
so it literally is one after the other. The actual work it&#39;s doing to g=
et the same answer is simply much greater and many many more clock cycles.<=
/div><div><br></div><div>If you took the same approach as numpy it&#39;s *p=
ossible* you *might* get something similarly fast. (But you&#39;d have a st=
eep learning curve and you&#39;d likely only optimise for one architecture.=
..)</div><div><br></div><div>Aside: What size is the *value*=C2=A0 the C ve=
rsion is creating? Well it&#39;s just (n * n+1 ) /2=C2=A0 - primary school =
triangular number stuff. So 50K is=C2=A01250025000 - which is a 31 bit numb=
er. So the C version will fail on a 32 bit machine as soon as you try over =
65536 as the argument... (On a 64bit=C2=A0machine admittedly the fall over =
number is admittedly higher... :-) )</div><div><br></div><div>C and C++ *ar=
e* faster than pure python. That&#39;s pretty much always going to be the c=
ase ( *except* for a specialising python compiler that compiles a subset of=
 python to either C/C++/Rust or assembler). However, python=C2=A0+ highly o=
ptimised C/C++/etc libraries will likely outperform naive C/C++ code - as y=
ou&#39;ve ably demonstrated here.</div><div><br></div><div>Why? Because whi=
le on the surface the two programs are vaguely similar - calculate=C2=A0the=
 triangular number of N, N times.=C2=A0 In practice, the way that they do i=
t is so different, you get dramatically different results.</div><div><br></=
div><div>As a bonus - you can get faster than both your num.py and C versio=
ns with pure python, by several orders of magnitude. You can then squeeze o=
ut a few more percent out of it.=C2=A0 Output from a pure python version of=
 a piece of code that performs the same operation - calculates the triangle=
 number of N, N times:</div><div><span style=3D"font-family:monospace"><spa=
n style=3D"font-weight:bold;color:rgb(84,255,84)"><br></span></span></div><=
div><span style=3D"font-family:monospace"><span style=3D"font-weight:bold;c=
olor:rgb(84,255,84)">michael@conceptual</span><span style=3D"color:rgb(0,0,=
0)">:</span><span style=3D"font-weight:bold;color:rgb(84,84,255)">~</span><=
span style=3D"color:rgb(0,0,0)">$ ./triangles.py 15000000
</span><br>time using pure python: 1.81 sec
<br>time using pure python &amp; memoisation: 1.7 sec<br>
<br></span></div><div>Note that&#39;s 15 million, not 50,000 - and it took =
the same time for my machine (recent core i7) as numpy did for you on your =
machine for just 50,000. That&#39;s not because I have a faster machine (I =
expect I don&#39;t).=C2=A0</div><div><br></div><div>What&#39;s different? W=
ell the pure python version is this - it recognises you were calculating=C2=
=A0 the triangular number for N and just calculates that instead :-)</div><=
div><span style=3D"font-family:monospace"><span style=3D"font-weight:bold;c=
olor:rgb(0,0,0)"><br></span></span></div><div><span style=3D"font-family:mo=
nospace"><span style=3D"font-weight:bold;color:rgb(0,0,0)">def </span><span=
 style=3D"color:rgb(0,0,0)">normaltriangle(n):
</span><br> =C2=A0=C2=A0=C2=A0<span style=3D"font-weight:bold;color:rgb(0,0=
,0)">return</span><span style=3D"color:rgb(0,0,0)"> (n*(n+</span><span styl=
e=3D"color:rgb(24,178,178)">1</span><span style=3D"color:rgb(0,0,0)">))/</s=
pan><span style=3D"color:rgb(24,178,178)">2</span><span style=3D"color:rgb(=
0,0,0)"> </span><br>
... called like this ..</span></div><div><span style=3D"font-family:monospa=
ce"><span style=3D"color:rgb(0,0,0)">=C2=A0 =C2=A0tm1=3Dit.timeit(stmt=3D</=
span><span style=3D"font-weight:bold;color:rgb(0,0,0)">lambda</span><span s=
tyle=3D"color:rgb(0,0,0)">: normaltriangle(count), number=3Dcount)
</span><br> =C2=A0=C2=A0=C2=A0print(f<span style=3D"color:rgb(24,178,178)">=
&quot;time using pure python: {round(tm1,2)} sec&quot;</span><span style=3D=
"color:rgb(0,0,0)">)</span><br>
<br></span></div><div><span style=3D"font-family:monospace">The (naive)=C2=
=A0memoisation=C2=A0version is this:</span></div><div><span style=3D"font-f=
amily:monospace"><br></span></div><div><span style=3D"font-family:monospace=
"><span style=3D"font-weight:bold;color:rgb(0,0,0)">def </span><span style=
=3D"color:rgb(0,0,0)">memoise(f):
</span><br> =C2=A0=C2=A0=C2=A0cache =3D <span style=3D"color:rgb(178,24,178=
)">{}</span><span style=3D"color:rgb(0,0,0)">
</span><br> =C2=A0=C2=A0=C2=A0<span style=3D"font-weight:bold;color:rgb(0,0=
,0)">def </span><span style=3D"color:rgb(0,0,0)">g(n):
</span><br> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0<span style=3D"font-w=
eight:bold;color:rgb(0,0,0)">if</span><span style=3D"color:rgb(0,0,0)"> n <=
/span><span style=3D"font-weight:bold;color:rgb(0,0,0)">in</span><span styl=
e=3D"color:rgb(0,0,0)"> cache:
</span><br> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0<span style=3D"font-weight:bold;color:rgb(0,0,0)">return</span><span sty=
le=3D"color:rgb(0,0,0)"> cache[n]
</span><br> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0<span style=3D"font-w=
eight:bold;color:rgb(0,0,0)">else</span><span style=3D"color:rgb(0,0,0)">:
</span><br> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0X =3D f(n)
<br> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0cach=
e[n] =3D X
<br> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0<spa=
n style=3D"font-weight:bold;color:rgb(0,0,0)">return</span><span style=3D"c=
olor:rgb(0,0,0)"> X
</span><br> =C2=A0=C2=A0=C2=A0<span style=3D"font-weight:bold;color:rgb(0,0=
,0)">return</span><span style=3D"color:rgb(0,0,0)"> g</span><br>
<br></span></div><div><span style=3D"font-family:monospace"><span style=3D"=
font-weight:bold;color:rgb(84,84,255)">@memoise</span><span style=3D"color:=
rgb(0,0,0)">
</span><br><span style=3D"font-weight:bold;color:rgb(0,0,0)">def </span><sp=
an style=3D"color:rgb(0,0,0)">triangle(n):
</span><br> =C2=A0=C2=A0=C2=A0<span style=3D"font-weight:bold;color:rgb(0,0=
,0)">return</span><span style=3D"color:rgb(0,0,0)"> (n*(n+</span><span styl=
e=3D"color:rgb(24,178,178)">1</span><span style=3D"color:rgb(0,0,0)">))/</s=
pan><span style=3D"color:rgb(24,178,178)">2</span><br><span style=3D"color:=
rgb(0,0,0)">
</span><br></span></div><div><span style=3D"font-family:monospace">... call=
ed like this ...</span></div><div><span style=3D"font-family:monospace"><sp=
an style=3D"color:rgb(0,0,0)">=C2=A0 =C2=A0tm2=3Dit.timeit(stmt=3D</span><s=
pan style=3D"font-weight:bold;color:rgb(0,0,0)">lambda</span><span style=3D=
"color:rgb(0,0,0)">: triangle(count), number=3Dcount)
</span><br> =C2=A0=C2=A0=C2=A0print(f<span style=3D"color:rgb(24,178,178)">=
&quot;time using pure python &amp; memoisation: {round(tm2,2)} sec&quot;</s=
pan><span style=3D"color:rgb(0,0,0)">)</span><br></span></div><div><br></di=
v><div><br></div><div>Original file containing both:</div><div><br></div><d=
iv><span style=3D"font-family:monospace"><span style=3D"color:rgb(24,178,24=
)">#!/usr/bin/python3</span><span style=3D"color:rgb(0,0,0)">
</span><br>
<br><span style=3D"font-weight:bold;color:rgb(0,0,0)">import</span><span st=
yle=3D"color:rgb(0,0,0)"> timeit </span><span style=3D"font-weight:bold;col=
or:rgb(0,0,0)">as</span><span style=3D"color:rgb(0,0,0)"> it
</span><br>
<br><span style=3D"font-weight:bold;color:rgb(0,0,0)">def </span><span styl=
e=3D"color:rgb(0,0,0)">memoise(f):
</span><br> =C2=A0=C2=A0=C2=A0cache =3D <span style=3D"color:rgb(178,24,178=
)">{}</span><span style=3D"color:rgb(0,0,0)">
</span><br> =C2=A0=C2=A0=C2=A0<span style=3D"font-weight:bold;color:rgb(0,0=
,0)">def </span><span style=3D"color:rgb(0,0,0)">g(n):
</span><br> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0<span style=3D"font-w=
eight:bold;color:rgb(0,0,0)">if</span><span style=3D"color:rgb(0,0,0)"> n <=
/span><span style=3D"font-weight:bold;color:rgb(0,0,0)">in</span><span styl=
e=3D"color:rgb(0,0,0)"> cache:
</span><br> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0<span style=3D"font-weight:bold;color:rgb(0,0,0)">return</span><span sty=
le=3D"color:rgb(0,0,0)"> cache[n]
</span><br> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0<span style=3D"font-w=
eight:bold;color:rgb(0,0,0)">else</span><span style=3D"color:rgb(0,0,0)">:
</span><br> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0X =3D f(n)
<br> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0cach=
e[n] =3D X
<br> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0<spa=
n style=3D"font-weight:bold;color:rgb(0,0,0)">return</span><span style=3D"c=
olor:rgb(0,0,0)"> X
</span><br> =C2=A0=C2=A0=C2=A0<span style=3D"font-weight:bold;color:rgb(0,0=
,0)">return</span><span style=3D"color:rgb(0,0,0)"> g
</span><br>
<br><span style=3D"font-weight:bold;color:rgb(84,84,255)">@memoise</span><s=
pan style=3D"color:rgb(0,0,0)">
</span><br><span style=3D"font-weight:bold;color:rgb(0,0,0)">def </span><sp=
an style=3D"color:rgb(0,0,0)">triangle(n):
</span><br> =C2=A0=C2=A0=C2=A0<span style=3D"font-weight:bold;color:rgb(0,0=
,0)">return</span><span style=3D"color:rgb(0,0,0)"> (n*(n+</span><span styl=
e=3D"color:rgb(24,178,178)">1</span><span style=3D"color:rgb(0,0,0)">))/</s=
pan><span style=3D"color:rgb(24,178,178)">2</span><span style=3D"color:rgb(=
0,0,0)">
</span><br>
<br>
<br><span style=3D"font-weight:bold;color:rgb(0,0,0)">def </span><span styl=
e=3D"color:rgb(0,0,0)">normaltriangle(n):
</span><br> =C2=A0=C2=A0=C2=A0<span style=3D"font-weight:bold;color:rgb(0,0=
,0)">return</span><span style=3D"color:rgb(0,0,0)"> (n*(n+</span><span styl=
e=3D"color:rgb(24,178,178)">1</span><span style=3D"color:rgb(0,0,0)">))/</s=
pan><span style=3D"color:rgb(24,178,178)">2</span><span style=3D"color:rgb(=
0,0,0)"> =C2=A0</span><br>
<br>
<br><span style=3D"font-weight:bold;color:rgb(0,0,0)">if</span><span style=
=3D"color:rgb(0,0,0)"> __name__ =3D=3D </span><span style=3D"color:rgb(24,1=
78,178)">&quot;__main__&quot;</span><span style=3D"color:rgb(0,0,0)">:
</span><br> =C2=A0=C2=A0=C2=A0<span style=3D"font-weight:bold;color:rgb(0,0=
,0)">import</span><span style=3D"color:rgb(0,0,0)"> sys
</span><br> =C2=A0=C2=A0=C2=A0count =3D int(sys.argv[<span style=3D"color:r=
gb(24,178,178)">1</span><span style=3D"color:rgb(0,0,0)">])
</span><br> =C2=A0=C2=A0=C2=A0tm1=3Dit.timeit(stmt=3D<span style=3D"font-we=
ight:bold;color:rgb(0,0,0)">lambda</span><span style=3D"color:rgb(0,0,0)">:=
 normaltriangle(count), number=3Dcount)
</span><br> =C2=A0=C2=A0=C2=A0print(f<span style=3D"color:rgb(24,178,178)">=
&quot;time using pure python: {round(tm1,2)} sec&quot;</span><span style=3D=
"color:rgb(0,0,0)">)
</span><br>
<br> =C2=A0=C2=A0=C2=A0tm2=3Dit.timeit(stmt=3D<span style=3D"font-weight:bo=
ld;color:rgb(0,0,0)">lambda</span><span style=3D"color:rgb(0,0,0)">: triang=
le(count), number=3Dcount)
</span><br> =C2=A0=C2=A0=C2=A0print(f<span style=3D"color:rgb(24,178,178)">=
&quot;time using pure python &amp; memoisation: {round(tm2,2)} sec&quot;</s=
pan><span style=3D"color:rgb(0,0,0)">)</span><br>
<br></span></div><div>I guess the point here is this: focussing on the lang=
uage/tool C vs python ignores how &quot;well&quot; the C code is written an=
d how &quot;well&quot; the python code is written.</div><div><br></div><div=
>However worrying about *that* rather than &quot;is there a smarter way of =
doing this&quot; means you can sometimes miss the 300 fold speed up (vs num=
py) or 6000 fold speed up (vs your python). I must admit as well, I was a l=
ittle surprised that the memoised version worked even this well with such s=
imple code.</div><div><br></div><div>But the point is when comparing C to n=
umpy, you&#39;re really comparing *your* C with *numpy&#39;s* C code, and a=
s you can see from their code, your repeated calls are very different from =
a vectorised call to CPU processor extensions designed specifically for thi=
s sort of work...</div><div><br></div><div>Gets even sillier (in a fun way =
:) ) if you can throw the code at several hundred GPU cores...</div><div><b=
r></div><div>Hope this was vaguely interesting...</div><div><br></div><div>=
<br></div><div>Michael.</div><div><br></div></div><br><div class=3D"gmail_q=
uote"><div dir=3D"ltr" class=3D"gmail_attr">On Fri, 25 Feb 2022 at 16:22, B=
ELAHCENE Abdelkader &lt;<a href=3D"mailto:[email protected]">abd=
[email protected]</a>&gt; wrote:<br></div><blockquote class=3D"gmai=
l_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,20=
4,204);padding-left:1ex"><div dir=3D"ltr"><div>Hi,</div><div>What do you me=
an?</div><div>the python and C programs are not equivalent?</div><div><br><=
/div></div><br><div class=3D"gmail_quote"><div dir=3D"ltr" class=3D"gmail_a=
ttr">Le=C2=A0ven. 25 f=C3=A9vr. 2022 =C3=A0=C2=A010:42, Giorgio Zoppi &lt;<=
a href=3D"mailto:[email protected]" target=3D"_blank">giorgio.zoppi@g=
mail.com</a>&gt; a =C3=A9crit=C2=A0:<br></div><blockquote class=3D"gmail_qu=
ote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,20=
4);padding-left:1ex"><div dir=3D"ltr">Well,<div>numpy is written in C :) Ma=
ybe your C is not the numpy equivalent?</div><div>Best Regards,</div><div>G=
iorgio</div></div><br><div class=3D"gmail_quote"><div dir=3D"ltr" class=3D"=
gmail_attr">Il giorno ven 25 feb 2022 alle ore 09:03 BELAHCENE Abdelkader &=
lt;<a href=3D"mailto:[email protected]" target=3D"_blank">abdelk=
[email protected]</a>&gt; ha scritto:<br></div><blockquote class=3D"gm=
ail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,=
204,204);padding-left:1ex"><div dir=3D"ltr">Hi,<br>a lot of people think th=
at C (or C++) is faster than python, yes I agree, but I think that&#39;s no=
t the case with numpy, I believe numpy is faster than C, at least in some c=
ases.<br><b>Is there another explanation ?<br>Or where can find =C2=A0a doc=
 speaking =C2=A0about the subject?<br></b>Thanks a lot <br>Regards<br>Numpy=
 implements vectorization for arrays, or I&#39;m wrong. Anyway here is an e=
xample Let&#39;s look at the following case:<br>Here is the result on my la=
ptop i3:<br><br>Labs$ <b>python3 tempsExe.py=C2=A0 50000</b> <br>=C2=A0 sum=
 with Python: 1250025000 and NumPy 1250025000<br>=C2=A0 =C2=A0 =C2=A0 time =
used Python Sum:=C2=A0<b> 37.28 sec </b><br>=C2=A0 =C2=A0 =C2=A0 time used =
=C2=A0Numpy Sum:=C2=A0 <b>1.85 sec</b><br><br>Labs$ <b>./tt =C2=A0=C2=A0 50=
000 	</b><br>=C2=A0<b> =C2=A0 CPU =C2=A0time :7.521730<br>=C2=A0 =C2=A0 The=
 value : 1250025000 <br></b>--------------------------------------------<br=
><br>This is the Python3 program :<br><br>import timeit as it<br>import num=
py as np<br>import sys<br>try :<br>	n=3Deval(sys.argv[1])<br>except:<br>	pr=
int (&quot;needs integer as argument&quot;) ; exit()<br>	<br>a=3Drange(1,n+=
1)<br>b=3Dnp.array(a)<br>def func1(): =C2=A0 =C2=A0 return sum(a)<br>def fu=
nc2():	 return np.sum(b)<br><br>print(f&quot;sum with Python: {func1()} and=
 NumPy {func2()} &quot;)<br>tm1=3Dit.timeit(stmt=3Dfunc1, number=3Dn)<br>pr=
int(f&quot;time used Python Sum: {round(tm1,2)} sec&quot;)<br>tm2=3Dit.time=
it(stmt=3Dfunc2, number=3Dn)<br>print(f&quot;time used =C2=A0Numpy Sum: {ro=
und(tm2,2)} sec&quot;)<br><br>and Here the C program:<br>#include &lt;time.=
h&gt;<br>#include &lt;stdio.h&gt;<br>#include &lt;stdlib.h&gt;<br>long func=
1(int n){<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 long =C2=A0r=
=3D0;<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 for (int =C2=A0i=3D1; i=
&lt;=3D n;i++) r+=3D i;<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
 return r;<br>}<br>int main(int argc, char* argv[]){<br>=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 clock_t c0, c1; <br>=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0 long v,count; int n;<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0 if ( argc &lt; 2) {<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 printf(&quot;Please give an argument&quot=
;);<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0 return -1;<br>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }<br>=C2=A0=C2=A0=C2=A0=
 n=3Datoi(argv[1]); <br>=C2=A0=C2=A0=C2=A0 c0 =3D clock();<br>=C2=A0=C2=A0=
=C2=A0=C2=A0 <b>for (int j=3D0;j &lt; n;j++)	v=3Dfunc1(n);</b><br>=C2=A0=C2=
=A0=C2=A0=C2=A0 c1 =3D clock();<br>=C2=A0=C2=A0=C2=A0=C2=A0 printf (&quot;\=
tCPU =C2=A0time :%.2f sec&quot;, (float)(c1 - c0)/CLOCKS_PER_SEC);<br>=C2=
=A0=C2=A0=C2=A0=C2=A0 printf(&quot;\n\tThe value : %ld\n&quot;, =C2=A0v);<b=
r>}<br></div>
_______________________________________________<br>
python-uk mailing list<br>
<a href=3D"mailto:[email protected]" target=3D"_blank">python-uk@python.=
org</a><br>
<a href=3D"https://mail.python.org/mailman/listinfo/python-uk" rel=3D"noref=
errer" target=3D"_blank">https://mail.python.org/mailman/listinfo/python-uk=
</a><br>
</blockquote></div><br clear=3D"all"><div><br></div>-- <br><div dir=3D"ltr"=
><div dir=3D"ltr">Life is a chess game - Anonymous.<br></div></div>
_______________________________________________<br>
python-uk mailing list<br>
<a href=3D"mailto:[email protected]" target=3D"_blank">python-uk@python.=
org</a><br>
<a href=3D"https://mail.python.org/mailman/listinfo/python-uk" rel=3D"noref=
errer" target=3D"_blank">https://mail.python.org/mailman/listinfo/python-uk=
</a><br>
</blockquote></div>
_______________________________________________<br>
python-uk mailing list<br>
<a href=3D"mailto:[email protected]" target=3D"_blank">python-uk@python.=
org</a><br>
<a href=3D"https://mail.python.org/mailman/listinfo/python-uk" rel=3D"noref=
errer" target=3D"_blank">https://mail.python.org/mailman/listinfo/python-uk=
</a><br>
</blockquote></div></div>

--0000000000009cf95105d8e1cf23--

--===============8837496801027313951==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
python-uk mailing list
[email protected]
https://mail.python.org/mailman/listinfo/python-uk

--===============8837496801027313951==--