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 <= <a href=3D"mailto:[email protected]">[email protected]= z</a>> 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's specifically compare the num.py and th= e 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 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's num.py'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't use num.py, and while= I'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'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'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 "add these, give me the result". And it'= ll be done. (OK there's a bit more to it, but that'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's also single threaded, and has no means of tel= ling 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 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's *p= ossible* you *might* get something similarly fast. (But you'd have a st= eep learning curve and you'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'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'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'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 & memoisation: 1.7 sec<br> <br></span></div><div>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).=C2=A0</div><div><br></div><div>What'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)">= "time using pure python: {round(tm1,2)} sec"</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)">= "time using pure python & memoisation: {round(tm2,2)} sec"</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)">"__main__"</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)">= "time using pure python: {round(tm1,2)} sec"</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)">= "time using pure python & memoisation: {round(tm2,2)} sec"</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 "well" the C code is written an= d how "well" the python code is written.</div><div><br></div><div= >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 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're really comparing *your* C with *numpy'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 <<a href=3D"mailto:[email protected]">abd= [email protected]</a>> 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 <<= a href=3D"mailto:[email protected]" target=3D"_blank">giorgio.zoppi@g= mail.com</a>> 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>> 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'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'm wrong. Anyway here is an e= xample Let'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 ("needs integer as argument") ; 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"sum with Python: {func1()} and= NumPy {func2()} ")<br>tm1=3Dit.timeit(stmt=3Dfunc1, number=3Dn)<br>pr= int(f"time used Python Sum: {round(tm1,2)} sec")<br>tm2=3Dit.time= it(stmt=3Dfunc2, number=3Dn)<br>print(f"time used =C2=A0Numpy Sum: {ro= und(tm2,2)} sec")<br><br>and Here the C program:<br>#include <time.= h><br>#include <stdio.h><br>#include <stdlib.h><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= <=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 < 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("Please give an argument"= ;);<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 < 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 ("\= tCPU =C2=A0time :%.2f sec", (float)(c1 - c0)/CLOCKS_PER_SEC);<br>=C2= =A0=C2=A0=C2=A0=C2=A0 printf("\n\tThe value : %ld\n", =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==--