next up previous contents
Next: Conversion to Maple Up: Implementation Previous: FORTRAN compiler limitations

Formatting C Expressions

 A function CAssign has also been implemented for producing assignments in C. Code resulting from Mathematica's CForm requires pre-processor statement, #include mdefs.h and the related include file to be accessible. If this statement is not specified, the compiler will be unable to correctly interpret the code produced by Mathematica. The include file mdefs.h is currently only distributed with Unix versions of Mathematica. CAssign makes the file redundant and adds many extra features.

Array indices in C start from zero. The option AssignIndex may be used to modify the starting index of arrays. Here is the default behaviour.

In[4]:= CAssign[a,{{x1,x2},{x3,x4}}]

Out[4]//OutputForm=
a[0][0]=x1;
a[0][1]=x2;
a[1][0]=x3;
a[1][1]=x4;
Each statement is terminated using a semi-colon via the option AssignEnd.

Powers in C are converted according to the following rules:

1.
Rational powers x1/2 and x-1/2 are converted to sqrt(x) and 1/sqrt(x) respectively.
2.
Remaining rational exponents and all integer exponents and are converted to floats.
The following example illustrates these.

In[5]:= CAssign[x^5-1/Sqrt[y]+z^(3/2)]

Out[5]//OutputForm= pow(x,5.)+pow(z,3./2.)-1./sqrt(y);
An array in Mathematica CForm can thus be incorrectly converted into a C function.

In[6]:= expr = Expand[(ArcCos[a[1]]-Sin[b[1]])^2];

In[7]:= CForm[expr]

Out[7]//CForm=
Power(ArcCos(a(1)),2) - 2*ArcCos(a(1))*Sin(b(1)) + Power(Sin(b(1)),2)
CForm actually converts Part to an array. In this example, the list a needs to be wrapped in HoldForm to prevent an evaluation warning message.

In[8]:= CForm[ HoldForm[ a[[3,2]] ] ]

Out[8]//CForm= a[3][2]

In[9]:= CForm[ a[[3,2]] ]

Part::partd: Part specification a[[3,2]]
     is longer than depth of object.

Out[9]//CForm= a[3][2]
What is actually required is to convert Mathematica arrays to C arrays. Since there is no distinction for arrays in Mathematica, it is not possible to perform this conversion automatically. Instead this is left up to the user via the option AssignToArray.

In[10]:= CAssign[expr,expr,AssignToArray->{a,b}]

Out[10]//OutputForm=
expr=pow(acos(a[1]),2.)+pow(sin(b[1]),2.)-2.*acos(a[1])*sin(b[1]);
Notice the line continuation character which is added.

Since the lhs may be specified as a string, assignment to array elements in C is possible.

In[11]:= CAssign["a[2][1]",Exp[b+ArcTan[c]]]

Out[11]//OutputForm=
a[2][1]=exp(b+atan(c));
When arrays are initialised in C, array elements that are not formally defined are defaulted to zero by a compiler [10]. Therefore, for the purposes of efficiency, it is desirable to remove unnecessary assignments and have them assigned by the compiler.

In[12]:= CAssign[a,{{0,b},{c,0}},AssignZero->False]

Out[12]//OutputForm=
a[0][1]=b;
a[1][0]=c;
Notice how the array indices correspond to the input.

There is a potential conflict with this option, when all assignments are zero-valued. In such a case, assignments to zeros are performed and an appropriate warning message is output.

In[13]:= CAssign[a,{0,0},AssignZero->False]

AssignZero::continue: 
   Expression encountered with no non-zero elements. Continuing with
     zero assignments.

Out[13]//OutputForm=
a[0]=0;
a[1]=0;
In some cases, C statement delimiters may not be required. For example if an expression is translated for use inside an if statement.
In[14]:= CAssign[a<=6||a>=-6,AssignEnd->""]

Out[14]//OutputForm=
a<=6.||a>=-6.
Although C compiler impose no restriction on the number of lines a single expression may occupy, it is often useful to break up large expressions for debugging purposes etc. The default for C is to generate an array of temporary variables t[1], t[2], etc. The global symbol AssignTemporaryIndex specifies the number of temporary variables introduced during each call to an Assign function.

Long expressions are broken up using the backslash character
. This is a preprocessor command which allows even token (the fundamental building blocks of C) to be broken up [10, section 2.1.2].

When writing C code, it is often useful to control the precision of data types in the following manner.

Some other points of note. The default Mathematica exponentiation is used for floating point numbers. Unlike FORTRAN, C does not possess complex data types. A complex structure must be declared in order to extend library functions (see section 5.6 of [10]).


next up previous contents
Next: Conversion to Maple Up: Implementation Previous: FORTRAN compiler limitations

Jorge Romao
5/14/1998