global
keyword
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:
;
" after each statement. Close the block with a "}".
return
keyword is found when evaluating the function, the value returned is a value of type void.
//
or #
. Everything after //
or after #
is discarded (until the end of line).
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:
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.
global
keywordCalcugator 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:
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:
If you need to create local variables, follow the pattern below:
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.
All arguments are passed by reference. The next example shows the feature.
Example:
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
.
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).
Operator | Description |
! a | Negates the boolean expression a . |
~ a | Negates the boolean expression a . |
- a | Changes the sign of expression a . |
int a | Removes 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^b | Raises a to the power b . |
a**b | Raises a to the power b . |
a*b | Computes the multiplication of a times b . |
a/b | Computes the division of a by b . |
a mod b | Computes the residue of dividing a by b . |
a cross b | Computes the cross product of vectors a and b . |
a dot b | Computes the dot product of vectors a and b . |
a + b | Computes the addition of a and b . |
a - b | Computes the subtraction of a and b . |
a < b | Returns true if a is smaller than b . |
a <= b | Returns true if a is smaller or equal to b . |
a > b | Returns true if a is greater than b . |
a >= b | Returns true if a is greater or equal than b . |
a == b | Returns true if a is equal to b . |
a != b | Returns true if a is not equal to b . |
a || b | Returns true if either a or b is true. |
a or b | Returns true if either a or b is true. |
a && b | Returns true if both a and b are true. |
a and b | Returns true if both a and b are true. |
a xor b | Exclusive or of operands a and b . |
a -> b | Returns the implication of a and b . |
a then b | Returns the implication of a and b . |
a iff b | Returns the equivalence of a and b . |
a = b | Assigns 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.
Operator | Precedence | Associates from the |
!, ~, -(unary), int | high | right |
++, -- | right | |
**, ^ | right | |
*, /, mod, cross | left | |
dot | left | |
+, - | left | |
<, <=, >, >= | left | |
==, != | left | |
||, or, &&, and, xor | left | |
->, then, iff | left | |
= | low | right |
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 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 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 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 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 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.
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.
Arrays can also behave like lists or stacks.
To create an empty list or stack named a
, do the following:
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:
The stack now has 4 elements:
To retrieve the data stored in the stack use the function pop
:
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:
a=()
defines a
to be an empty stack or list.
push(a,b)
pushes object b
on "top" of the stack a
.
x=pop(a)
returns the last pushed object on the stack a
removing it from the stack.
x=peek(a)
returns the last "pushed" object on the stack a
without removing it.
size(a)
returns the number of objects stored on the stack a
.
pushf(a,b)
pushes object b
at the "front" of the stack a
.
x=popf(a)
returns the object at the "front" of the stack and removes it from the stack a
.
x=peekf(a)
returns the object at the "front" of the stack a
without removing it.
You may use arrays as lists too. List oriented functions are:
insert(a, value, index)
inserts object value
at index index
in array a
.
remove(a, index)
removes the object located at index index
in array a
.
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:
Using the program condition
we obtain:
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:
Using the condition2
program we obtain:
Predicates are a set a query functions used inside programs. These functions may i nform about the type or value of an object.
isArray(obj)
returns true if object obj
is an array.
isBool(obj)
returns true if object obj
stores a boolean value.
isComplex(obj)
returns true if object obj
is a complex number.
isContinuousDistribution(obj)
returns true if obj
is a continuous distribution object.
isDiagonal(obj)
returns true if obj
is a diagonal matrix.
isDiscreteDistribution
returns true if obj
is a discrete distribution object.
isDistribution
returns true if obj
is a distribution object.
isEven(obj)
returns true if object obj
is an even integer.
isFunction(obj)
returns true if object obj
is a function (library or user defined).
isHermitian
returns true if obj
is a Hermitian matrix.
isInteger(obj)
returns true if object obj
is an integer.
isMatrix(obj)
returns true if object obj
is a matrix.
isOdd(obj)
returns true if object obj
is an odd integer.
isPositiveDefinite
returns true if obj
is a positive definite matrix.
isRational(obj)
returns true if object obj
is a rational number.
isReal(obj)
returns true if object obj
is a real number but it is not integer nor rational.
isScalar(obj)
returns true if object obj
is a scalar. An object is scalar if it is real or complex or integer or rational.
isString(obj)
returns true if object obj
is a string.
isSymmetric
returns true if obj
is a symmetric matrix.
isUnity
returns true if obj
is unity or a unitary matrix.
isVector(obj)
returns true if object obj
is a three-dimensional vector.
isZero(obj)
returns true if object obj
is zero scalar or zero matrix.
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:
//---------------------- // 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.