This is a short introduction into compiled C code in Euler. Compiled code is usually much faster than Euler code, and can be imported from other sources more easily. Euler can load DLL (dynamic link library) files, and call the functions exported in these libraries. These libraries must be Windows DLLs from any compiler that can bind to a library. To make it easy, Euler comes with tccompile a Tiny C Compiler. See the documentation about more details on this compiler. Here is a first benchmark. The recursive version of fib computes the Fibonacci numbers in a very inefficient way. But it is good to measure the overhead of calling a function. The following compiler call will not work, unless you have write access to the current directory. For the introduction notebook, this usually not the case. You have to copy the notebook and the fib.c file into a directory with write access (see below).
>// tccompile fib
The code for fib in fib.c is the following: double hfib (int n) { if (n<2) return n; return hfib(n-1)+hfib(n-2); } There are more functions for the communication with Euler. But we cover those later. We load the DLL with the following command. The parameters are: DLL-name, function-name, number-of-parameters.
>dll("fib","fib",1);
The running time is 1/20 second.
>tic; fib(30), toc;
832040 Used 0.047 seconds
Here is the same function in Euler.
>function efib(n) ...
if n<2 then return n; endif; return efib(n-1)+efib(n-2); endfunction
The running time is much worse (15 seconds on my computer).
>tic; efib(30), toc;
832040 Used 14.664 seconds
By the way, I checked it on Matlab, and it was even longer (24 seconds). It should be noted, that the iterative version is much better, even if we use the utility function sequence.
>tic; sequence("x[n-1]+x[n-2]",[1,1],30), toc;
[ 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025 121393 196418 317811 514229 832040 ] Used 0.031 seconds
We should explain the functions in the DLL which handle the communication with Euler. The complete content of fib.c is the following.
>printfile("fib.c");
#include "dlldef.h" #include <stdio.h> double hfib (int n) { if (n<2) return n; return hfib(n-1)+hfib(n-2); } EXPORT char * fib (header *hd[], int np, char *ramstart, char *ramend) { start(ramstart,ramend); // required !!! int n=getint(hd[0]); IFERROR("Need an integer"); new_real(hfib(n)); return newram; } EXPORT char * fibv (header *hd[], int np, char *ramstart, char *ramend) { start(ramstart,ramend); // required !!! int n=getint(hd[0]); IFERROR("Need an integer"); CHECK(n>1,"Need an interger >1"); header *res=new_matrix(1,n+1); double *m=matrixof(res); m[0]=0; m[1]=1; int i; for (i=2; i<=n; i++) m[i]=m[i-1]+m[i-2]; return newram; }
As you see, the exported functions get an array of Euler headers, the number of parameters, and two pointers to the current start of the Euler stack and its end. Euler calls two other functions in the DLL, which are exported in the dlldef.c file. Have a look at the documenation for more information. See: ../documentation/compile There are some more useful examples of C code on the following pages. See: Examples/Mandelbrot See: Examples/Distribution of Primes
If you develop your own DLLs, you need to unload the DLL before you compile a new version.
>closedll("fib");
If you want to test the following compiler, press F10 on the command line. This will open the external editor with fib.c loaded. Save the file to your desktop. Then save this notebook to the desktop, close it and open it again.
>tccompile fib;
Most likely you want to put the following line to an Euler file. Then the user can simply load the Euler file with load fib and run all DLL commands.
>dll("fib","fib",1);
You can also provide pseudo functions, which only serve as a comment line.
>function comment fib (n:integer) ...
## compute the n-th Fibonacci number recursively endfunction
The user will now get help, and also find the function in the status line.
>help fib
fib is an Euler function. function fib (n: integer) Entered from command line. compute the n-th Fibonacci number recursively Search Maxima for help: fib (<n>) For more information try: mxmhelp fib
For a test, we add a more efficient version of fib.
>closedll("fib"); tccompile fib; dll("fib","fibv",1);
The function now looks like this. EXPORT char * fibv (header *hd[], int np, char *ramstart, char *ramend) { start(ramstart,ramend); // required !!! int n=getint(hd[0]); IFERROR("Need an integer"); CHECK(n>1,"Need an interger >1"); header *res=new_matrix(1,n+1); double *m=matrixof(res); m[0]=0; m[1]=1; int i; for (i=2; i<=n; i++) m[i]=m[i-1]+m[i-2]; return newram; } We generate a matrix on the stack, and fill it with the Fibonacci numbers. The running time cannot be measured in seconds.
>tic; v=fibv(30); toc;
Used -2.90878e-014 seconds