Programming

  1. Overview
  2. The global keyword
  3. Argument passing
  4. Operators
  5. The if statement
  6. The for statement
  7. The while statement
  8. The do-while statement
  9. The switch statement
  10. The return statement
  11. Using arrays, lists, stacks
  12. Predicates
  13. Examples

Overview

User defined functions may be transformed into programs by using the if, if-else, for, while, return, break, switch, do-while and continue statements along with the opening "{" and closing "}" brackets.

Printing intermediate values is done by using functions printf(), sprintf(), print(), or println().

The basic rules are:

Here is an simple example program that finds the roots of a quadratic equation of the form a*x^2 + b*x + c = 0. Notice that this program is a function that returns either a scalar value or a vector depending on the value of a.

   //------------------------------------------
   // Roots of a quadratic equation 
   //------------------------------------------
   quaroot(a,b,c) = {
      if( a==0 ) {
         println( "a == 0." );
         return -c/b;
      }
      x1 = (-b + sqrt(b*b-4*a*c))/(2*a);
      x2 = (-b - sqrt(b*b-4*a*c))/(2*a);
      return (x1, x2);
   }

User defined function can be used like any other library function:


a=3; b=2; c=-3;
quaroot(a,b,c)
0.7208  -1.3874

You may create functions using other used defined functions. The next example program plots the quadratic function and prints the roots.

   //------------------------------------------
   // Plot and roots, quadratic equation 
   //------------------------------------------
   quaplot(a,b,c) = {
      x = quaroot(a,b,c);
      sort(x);
      x1 = x[1];
      x2 = x[2];
      println( "Plot of quadratic equation" );
      println( "Roots are:" );
      println( "x1=", x1, " x2=", x2 );

      if( x1.isComplex() ) {
         x1 = 0;
         x2 = 10;
      }
      else {
         x1 = x1-2;
         x2 = x2+2;
      }

   // Create the function and plot it
      f(x) = a*x*x + b*x + c;
      plot( f, x1, x2, 100, "red", "canvas:lightGray" );
   }

Next example is a function that modifies the calling argument.

   //------------------------------------------
   // Modify calling argument 
   //------------------------------------------
   g(x) = {
      if( x<0 )
         x = -x;
      else
         x = x*x;
      return x;
   }

An example of using this function follows.


a = 8
8
g(a)
64
a
64

The global keyword

Calcugator programs have a different rule than simple user-defined functions.

While simple functions resolve symbols by looking into the global scope, user-defined programs look in the local scope. The next example shows this issue:


a = 8
8
f(x)={ return x*a; }
      Identifier "a" is not defined.
      f(x)={ return a*x; }
                    ^

The reason for the error above is that variable a was not found in the local scope of function f. If you need to access variables located in the global scope, use the global keyword:


a = 8
8
f(x)={ global a; return x*a; }
f(x)={ global a; return x*a; }
f(3)
24

If you need to create local variables, follow the pattern below:


a = 8
8
f(x)={ a=3; return x*a; }
f(x)={ a=3; return x*a; }
f(5)
15
a
8

Notice that in the example above there are two variables with the same name. Variable a located in the global scope has a value equal to 8 while variable a located in the local scope of function f has a value of 3.

Notice that the value of a in the global scope was not modified.

There is no need to use the global keyword to access library functions or user-defined functions.

Argument passing

All arguments are passed by reference. The next example shows the feature.

Example:


f(x)={ if(x<0) x=x*x; else x=x+4; return x; }
f(x)={ if(x<0) x=x*x; else x=x+4; return x; }
a = 5
5
f(a)
9
a
9
f(3)
7

Notice that the call f(a) changed the value of variable a. The reason is that variable x in scope of function f becomes a reference of variable a.

Also notice the call to f(3). In the latter call, Calcugator takes care of the making variable x a reference to a temporary variable that is initialized with the value 3.

Operators

Calcugator implements a basic set of operators allowing the construction of expressions involving matrices, arrays, vectors, complex numbers, real numbers, and boolean values. Some operators have synonyms, for example the exponential operator is either ^ or ** (for the nostalgic FORTRAN lover).


OperatorDescription
! aNegates the boolean expression a.
~ aNegates the boolean expression a.
- aChanges the sign of expression a.
int aRemoves the decimal part of expression a.
++a, a++Increments a by one. See Note 1 below.
--a, a--Decrements a by one. See Note 1 below.
a^bRaises a to the power b.
a**bRaises a to the power b.
a*bComputes the multiplication of a times b.
a/bComputes the division of a by b.
a mod bComputes the residue of dividing a by b.
a cross bComputes the cross product of vectors a and b.
a dot bComputes the dot product of vectors a and b.
a + bComputes the addition of a and b.
a - bComputes the subtraction of a and b.
a < bReturns true if a is smaller than b.
a <= bReturns true if a is smaller or equal to b.
a > bReturns true if a is greater than b.
a >= bReturns true if a is greater or equal than b.
a == bReturns true if a is equal to b.
a != bReturns true if a is not equal to b.
a || bReturns true if either a or b is true.
a or bReturns true if either a or b is true.
a && bReturns true if both a and b are true.
a and bReturns true if both a and b are true.
a xor bExclusive or of operands a and b.
a -> bReturns the implication of a and b.
a then bReturns the implication of a and b.
a iff bReturns the equivalence of a and b.
a = bAssigns a copy of b to a.

Note 1: The decrement/increment operators are limited to a expressions with a single identifier.


Strict rules of precedence and associativity are enforced when parsing expressions. The table below shows the rules adopted by the Calcugator language.

OperatorPrecedenceAssociates from the
!, ~, -(unary), inthighright
++, -- right
**, ^ right
*, /, mod, cross left
dot left
+, - left
<, <=, >, >= left
==, != left
||, or, &&, and, xor left
->, then, iff left
=lowright

The if statement

The if statement has two forms:

   if( test ) expr;

   if( test ) expr1; else expr2;

Expression test must be a boolean expression. Any of the expressions expr, expr1 and expr2 can be a single statement or a block of statements. You may nest if statements.

Example:

   if( x<0 )
      return "x is negative";

Example:

   if( x<0 and -2<x )
      return;
   else
      x++;

Example:

   p = q or (x>0);
   if( p )
      if( q ) {
         x = 2;
         y = sqrt(s*s-2);
      }
      else
         return "No";
   else
      print( "No data" );

The for statement

The form of the for statement is:

   for( expr1; test; expr2 ) expr3;

Expression test must be a boolean expression. Both expressions expr1 and expr2 must be single expressions. Calcugator does not define a comma (",") operator like C/C++. Expression expr3 may be a single expression or a block of expressions.

Example:

   j = size(a);
   for( i=1; i<n and i<j; i++ ) {
      s = s + i*j;
      a[i] = a[i]*s;
   }

A continue statement forces a loop and a break statement causes an immediate exit of the loop.

Example:

   for( i=1; i<n; i++ ) {
      if( i==n )
         continue;
      a[i] = a[i]*s;
      if( a[i]<=0 )
         break;
   }

The while statement

The form of the while statement is:

   while( test ) expr;

Expression test must be a boolean expression and expression expr may be a single expression or a block of expressions.

Example:

   p = q or r;
   while( p ) {
      if( q ) 
         i++;
      else {
         p = a[i]>a[j];
         q = (a[i] mod 2)==0;
      }
   }

A continue statement forces a loop and a break statement causes an immediate exit of the loop.

Example:

   while( isComplex(z[i]) ) {
      println( "z=", z[i] );
      z[i] = z[i] + 0.25j;
      i++;
      if( abs(z[i])<1 )
         continue;
      if( i>10 )
         break;
   }

The do-while statement

The form of the do-while statement is:

   do exrp; while( test );

Expression expr may be a single expression or a block of expressions. Expression test must be a boolean expression.

Example:

   p = q or r;
   do {
      if( q ) 
         i++;
      else {
         p = a[i]>a[j];
         q = (a[i] mod 2)==0;
      }
   } while( p and q );

A continue statement forces a loop and a break statement causes an immediate exit of the loop.

Example:

   do {
      println( "z=", z[i] );
      z[i] = z[i] + 0.25j;
      i++;
      if( abs(z[i])<1 )
         continue;
      if( i>10 )
         break;
   } while ( isComplex(z[i]) );

The switch statement

The switch statement has two forms:

   switch( expr ) {
      case test_1 :
         expr_1;
      case test_2 :
         expr_2;
      ...
      case test_n :
         expr_n;
   }

   switch( expr ) {
      case test_1 :
         expr_1;
      case test_2 :
         expr_2;
      ...
      case test_n :
         expr_n;
      default :
         default_expr;
   }

Expression expr must be a single expression. Expressions test_1, test_2,... test_n must be single expressions. Expressions expr_1, expr_2,... expr_n and default_expr can be single expressions or block of statements. Consult a C/C+++/java reference to learn on how a switch statement works.

Example:

   switch( x<y ) {
      case true:
         println( "It's true" );
         break;
      case false:
         println( "It's false" );
         break;
   }

Example:

   switch( t ) {
      case x+y:
         a = 9;
         break;
      case abs(z):
         a = 8;
         break;
      default:
         a = 7;
   }

Calcugator's implementation is a generalization of the C/C++ switch version for it allows non integer and non constants expressions. The use of a break statement is supported as well as the use of "cascading" cases.

Example:

   switch( true ) {
      case x<y :
      case isVector(z):
         return s;
      case y>=x :
      case !isVector(z) :
         return t;
   }

The return statement

The return statement works like in C/C++/java. However, Calcugator allows functions to return different types from the same function including function objects.

Next example illustrates the case in which you can create your own sin function following MATLAB's1 conventions. Let's call the function Sin:

Example:

   Sin( a ) = {
      if( isArray(a) or isMatrix(a) ) {
         // Work on a copy     
         acopy = a;
         return apply(acopy,sin);
      }
      if( isScalar(a) )
         return sin(a);
   }

Function Sin defined above returns an array or a matrix or a scalar depending on the argument used. For any other type, the result would be void.


a = pi/2;
Sin(a)
1.0
b = ( pi/2, -pi/2 );
Sin(b)
1.0  -1.0

The following function illustrates how returning functions may be very helpful. Let's assume we want to compute a function that computes the central derivative of a given function.

Example:

   CentralDeriv( f, h ) = {   
      df(x) = (f(x+h)-f(x-h))/(2*h);
      return df;
   }

We test this function with the library function sin using h=0.0001. A check is made using the fact that cos is the exact derivative.


dsin = CentralDeriv( sin, 0.0001 )
dsin(x) = (sin(x + 0.0001) 
- sin(x - 0.0001) / (2 * 0.0001);
dsin(.7)
0.7648
cos(.7)
0.7648

Using arrays, lists, stacks

Arrays can also behave like lists or stacks.

To create an empty list or stack named a, do the following:


a=()
()

Array a is now an empty stack or list. Let's use array a as an stack.

You may now push any kind of value on "top" of the stack. For example, we may push a string, some numbers and an array:


push(a, "ABC")
"ABC"
push(a, 4/5)
"ABC"  4/5
push(a, 7.2)
"ABC"  4/5  7.2
push(a, (3,3))
"ABC"  4/5  7.2  ( 3, 3 )

The stack now has 4 elements:


size(a)
4

To retrieve the data stored in the stack use the function pop:


x = pop(a)
3  3

The call to pop removes the last pushed element on the stack. The size of the stack reduces by one.

You may use these functions with stacks and lists:

You may use arrays as lists too. List oriented functions are:

Using an array as a list or as an stack doesn't stop you from using the square brackets to modify or use any entry of the array.

Example:

Given an input array a, the program below returns an array with all entries a[i] such that a[i]<5:

// --------------------------------------
// Given array "a", returns an array with
// all entries smaller than 5
// --------------------------------------
condition(a) = {
   b = ();           // Empty stack
   for( i=1; i<=size(a); i=i+1 ) {
      c = a[i];
      if( c<5 )     // Test if c is smaller than 5
         push(b, c);
   }
   return b;
}

For example, given:


a=(9, 4, 1, 3, 7, 8, 2, 6)
9  4  1  3  7  8  2  6

Using the program condition we obtain:


b = condition(a)
4  1  3  2

What if we need to return all entries that hold a condition other than "less than 5"? In that case you may change the test condition in the program but a better solution consist of passing the condition as a function.

The new version is as follows:

// --------------------------------------
// Given array "a", returns an array with
// all entries "x" such "f(x)" is true.
// --------------------------------------
condition2(a, f) = {
   b = ();           // Empty stack
   for( i=1; i<=size(a); i=i+1 ) {
      c = a[i];
      if( f(c) )     // Test if f(c) is true
         push(b, c);
   }
   return b;
}

Let's test this program using the condition "greater than 5". A suitable function is:


f(x) = x>5
 f(x) = x>5

Using the condition2 program we obtain:


b= condition2(a, f)
9  7  8  6

Predicates

Predicates are a set a query functions used inside programs. These functions may i nform about the type or value of an object.

To test for unity, zero, infinity or NaN, you may directly compare an object with 1, 0, Infinity or NaN using the comparison operators. For example:


x=-1/0
-Infinity
5>x
 true
Infinity==NaN
false

Examples

//----------------------
// Factorial of a number
//----------------------
f(x) = {
   if( !isInteger(x) )
      return "Argument must be an integer";
   if( x==1 || x==0 ) return 1;
   if( x<0 )
      return "Integer must be 0 or bigger";
   y = x;
   res = 1;
   while( y>1 ) {
      res = res*y;
      y = y - 1;
   }
   return res;
}


#----------------------------------------------
# Root of a function. Bisection method
# notice function f(x) is passed as a parameter
#----------------------------------------------
root( f, a, b, tol ) = {
   fa = f(a);
   fb = f(b);
   if( fa * fb > 0 )
      return "Can not find a root in given interval";
   x  = (a + b)/2.;
   fx = f(x);
   while( abs(fx) > tol ) {
      if( fa * fx < 0 ) {
         fb = fx;
         b  = x;
      }
      else {
         fa = fx;
         a  = x;
      }
      x  = ( a + b )/2.;
      fx = f(x);
   }
   return x;
}

(1) MATLAB © is a registered mark of the MathWorks.