Back: 4.6 Array ranges Forward: 4.7.1 Arithmetic-assignment operators   FastBack: 4. EDL Up: 4. EDL FastForward: 5. Built-in Functions         Top: fsc2 Contents: Table of Contents Index: Index About: About This Document

4.7 Arithmetic

Of course, fsc2 understands the usual arithmetic operations, i.e. addition, subtraction, multiplication and division, represented by the characters `+', `-', `*' and `/'. They can be used with simple integer and floating point values as well as with 1-dimensional arrays (see below for more information). If one of the values is a floating point value the result is also a floating point number - only if both values are integers the result is also an integer. This also holds for the division - if you divide two integers the result is still an integer, see below.

Some care has to be taken in arithmetic with integers. The range of values an integer variable can have is restricted to the interval [-2147483648, +2147483647], i.e. [-2^31, 2^31 - 1] (at least on a 32-bit processor). Thus, it isn't to difficult to create numbers with greater values, e.g. by multiplication, that can't be represented by an integer! In this case the result of the operation will be completely bogus, e.g.

 
1000000 * 3000 = -1294967296

(There is actually some logic behind this result but that doesn't help too much.) So, if you suspect the result of an integer operation to exceed the range of representable values, convert the values to floating point type (using the function float()) before you do the potentially problematic arithmetic operation.

Of course, there are also limits to the range of numbers representable by a floating point number. Fortunately, these limits are much larger - typically the maximum size of floating point numbers is in the range of 10^300.

Another important point about calculations involving integers concerns the division. The result of the division of two integer values is again an integer value. For non-integer results this is achieved by simply truncating the digits following the decimal point. Thus, typical results are

 
7 / 2 = 3     8 / 3 = 2     -7 / 2 = -3

To avoid this truncation convert at least one of the values used in the division to a floating point type by using the float() function, i.e.

 
float( 7 ) / 2 = 3.5    8 / float( 3 ) = 2.666666667

Beside the normal arithmetic operations there are two often needed operations, the modulo function and the exponentiation. For the modulo operation the percent sign % is used and the result is the remainder of the division, e.g.

 
7 % 3 = 1         6.5 % 2.5 = 1.5 

For the exponentiation the caret character ^ is to be used, e.g.

 
3^2 = 9           6.5^1.5 = 16.5718134219...

As mathematics dictate non-integer exponents can only be used with non-negative bases!


Back: 4.7 Arithmetic Forward: 4.7.2 Operator precedence   FastBack: 4. EDL Up: 4.7 Arithmetic FastForward: 5. Built-in Functions         Top: fsc2 Contents: Table of Contents Index: Index About: About This Document

4.7.1 Arithmetic-assignment operators

When assigning to a variable usually the assignment operator `=' is used. But there are often cases where a variable just has to be incremented as in variable:

 
I = I + 1;

This assignment can be shortened (and sometimes made more readable) by using the `add and assign' operator `+=':

 
I += 1;

Assignment operators mixed with arithmetic can also be used with all other arithmetic operators, i.e. you may use all of the following assignment operators

 
+=     -=     *=     /=     %=     ^=

Back: 4.7.1 Arithmetic-assignment operators Forward: 4.7.3 Arithmetic with arrays and matrices   FastBack: 4. EDL Up: 4.7 Arithmetic FastForward: 5. Built-in Functions         Top: fsc2 Contents: Table of Contents Index: Index About: About This Document

4.7.2 Operator precedence

Usually one doesn't need to think about the precedence of operators. We already learned in primary school that multiplication and division have higher precedence than addition and subtraction and, of course, a programming language should follow these rules. But sometimes there are cases where it is necessary to know the precedence exactly, i.e. the exact sequence an expression is evaluated.

The unary operators (unary in the sense that they apply only to one number or variable) `+' and `-', i.e. the operators defining the sign of a number, have the highest precedence. There is a further operator, to be discussed later, having the same precedence, the logical negation operator, `!'. The evaluation of an expression with more than one of these operators is from the right to the left, i.e.

 
 !-x    will be treated as if written as    ! ( - x )

(This is not a very useful example but here for sake of completeness.)

The exponentiation operator, `^', has the next highest precedence, i.e. it binds more tightly than any other binary operator (i.e. an operator involving two numbers or variables). If there is more than one of these operators in a row the expression will be evaluated from the right to the left:

 
 2^3^4    will be treated as if written as    2^(3^4)

The operator with the next lower precedence is the modulo operator, `%'. Expressions with more than one `%' in a row will be evaluated left to right, i.e.

 
 31 % 6 % 2    will be treated as if written as    ( 31 % 6 ) % 2

Now follow the multiplication and division operators, `*' and `/. Both have exactly the same precedence and expressions involving more than one of these operators are evaluated left to right, i.e.

 
 3 * 20 / 7    will be treated as if written as    ( 3 * 20 ) / 7

(Take care: The order of evaluation can make a lot of a difference - due to the rules of integer division (3 * 20) / 7 will evaluate to 8, while 3 * (20 / 7) would result in 6).

The next lower precedence operators are the addition and subtraction operators, `+' and `-'. Also for these operators expressions involving more than one of these operators are evaluated left to right:

 
 13 + 4 - 5    will be treated as if written as    ( 13 + 4 ) - 5

Usually, this won't matter a lot, but if you're dealing with very large numbers and there's danger of an overflow to occur knowing the rules of evaluation can become important.

The next lower precedence operators are the logical operators to be discussed in more detail below, i.e. the logical and operator, `AND' or `&', the logical or operator, `OR' or `|' and the logical exclusive or (xor) operator, `XOR' or `~'. Expressions containing more than one of these operators are always evaluated from the left to the right of the expression:

 
 a OR b AND c  will be treated as if written as  ( a OR b ) AND c

or

 
 a | b & c     will be treated as if written as  ( a | b ) & c

To make your intentions more clear to human readers of your EDL scripts it's probably a good idea to use parenthesis in these cases even if they are not strictly required.

The operators with the second-lowest precedence are the comparison operators (also the be discussed below in more detail), i.e. the test for equality, `==' (not to be confused with the assignment operator `='), the test for inequality, `!=', and the remaining four comparison operators `<', `<=', `>' and `>=', i.e. less than, less or equal, larger and larger or equal. If more than one of these operators appears in an expression evaluation is done left to right.

Finally, the lowest precedence has the conditional operator, which has the form

 
expression_1 ? expression_2 : expression_3

It tests expression_1 and then results in expression_2 being evaluated if the result of the test was non-zero, or in expression_3 being calculated if the test failed (i.e. resulted in a zero value), a more detailed explanation is given below.

Actually, there are also the assignment operators. But these are only used after all of the other operators have been evaluated, so there is never a necessity to enclose the right hand of an equation in parenthesis. And since only one assignment operator is allowed in a statement you don't have to worry about the order of evaluation.

Of course, the precedence of operators and the sequence they are evaluated in can always be changed by using parentheses. So, if in doubt, use parentheses - this won't slow down the program but will often make the script easier to understand.


Back: 4.7.2 Operator precedence Forward: 4.8 Conditional operator   FastBack: 4. EDL Up: 4.7 Arithmetic FastForward: 5. Built-in Functions         Top: fsc2 Contents: Table of Contents Index: Index About: About This Document

4.7.3 Arithmetic with arrays and matrices

Beside the usual arithmetic with numbers it is also possible to use whole arrays and more-dimensional matrices in arithmetic expressions. Lets start with 1-dimensional arrays. As long as the sizes of the two arrays are identical they can be added or subtracted as if they were numbers. For example, if the arrays a and b are defined as

 
  a[ 3 ] = { 0.5,  1.0,  2.0 };
  b[ 3 ] = { 1.0, -2.0, -3.0 };

they can be added and subtracted in an element-by-element fashion, resulting in

 
  a + b      ->   {  1.5, -1.0, -1.0 }
  a - b      ->   { -0.5,  3.0,  5.0 }

Of course, you can also invert the sign of all the elements of an array by simply prepending it with a minus sign

 
  -a         ->   { -0.5, -1.0, -2.0 };

But it's also possible to add a number to each of the elements of an array or to subtract a number (or to subtract all array elements from a number):

 
  a + 5      ->   { 5.5, 6.0, 7.0 }
  a - 3      ->   { -2.5, -2.0, -1.0 }
  3 - a      ->   { 2.5, 2.0, 1.0 }

Multiplication and division are also possible with whole arrays. Again, these operations are implemented in an element-by-element way, i.e. multiplying two arrays is not a dot product but results again in an array of the same size as both the original arrays. The same holds for the division. With the arrays a and b defined above the results are:

 
  a * b      ->   { 0.5, -2.0, -6.0 }
  a / b      ->   { 0.5, -0.5, -0.666667 }
  b / a      ->   { 2.0, -2.0, -1.5 }

Multiplication and division of an array with a number is also defined as shown here:

 
  a * 2      ->   { 1.0, 2.0, 4.0 }
  a / 3      ->   { 0.166667, 0.333333, 0.666667 }
  3 / a      ->   { 6.0, 3.0, 1.5 }

Finally, calculation of the modulo function and exponentiation can be done with whole arrays. These operations are again implemented as element-by-element calculations, i.e. always resulting in an array:

 
  a % b      ->   { 0.5, 1.0, 2.0 }
  b % a      ->   { 0.0, 0.0, -1.0 }
  a ^ b      ->   { 0.5, 1.0, 0.125 }
  b ^ a      ->   { 1.0, -2.0, 9.0 }

Of course, the same operations can also be applied to a mixture of arrays and simple numbers, also resulting in arrays:

 
  a % 0.3    ->   { 0.2, 0.1, 0.2 }
  1.3 % a    ->   { 0.3, 0.3, 0.7 }
  a ^ 2      ->   { 0.25, 1.0, 4.0 }
  2 ^ a      ->   { 1.414215, 2.0, 4.0 }

All these kinds of arithmetics also work with more-dimensional arrays. If the size of two matrices are identical they can be added together or subtracted from each other, then elements can be multiplicated or divided in an element by element fashion (take care, multiplication of two 2-dimensional matrices does don't work in the usual mathematical way, but the first elements of the first rows of both matrices get multiplicated, forming the first element of the first row of the resulting matrix). And also the modulo and exponentiation operations work as well as the negation.

And as for 1-dimensional arrays a single number can be e.g. added to each of the elements of a more-dimensional array. I.e. if M is a 3-dimensional matrix you can add the number 3 to each of it's elements (as far as they exist yet in the case of variable sized matrices) by simply writing

 
M += 3;

Of course, this also works with all the other kinds of arithmetic operations. The only requirement is, if M is a variable sized matrix, all elements exist, i.e. if for example a sub-array isn't yet defined fsc2 will flag an error because it doesn't know how to add a number to an array that not exists yet.

If you want to add a number to only a sub-array of the matrix

 
M[ 2 ] += 3;

would add 3 to each elements of the 2nd sub-array of M (which is a matrix of rank 4x5).

But you can also add a whole 1-dimensional array to each of the sub-arrays of a matrix. Lets again assume that M 3-dimensional, e.g. a matrix of rank 3x4x5. If a is now an 1-dimensional array of length 5 you can add it to all of M's 12 sub-sub-arrays by writing

 
M += a;

If you would have to write the same using just the elements you would have to write 60 additions instead, i.e.

 
M[ 1, 1, 1 ] += a[ 1 ];
M[ 1, 1, 2 ] += a[ 2 ];
...
M[ 1, 1, 5 ] += a[ 5 ];
M[ 1, 2, 1 ] += a[ 1 ];
...
...
M[ 3, 4, 5 ] += a[ 5 ];

Of course, this could also be done using a FOR loop, see below, but would still be a lot longer.

If you instead want to add the array a only to all the sub-array in the 2nd set of sub-arrays of M you could simply write

 
M[ 2 ] += a;

instead of doing it explicitely in the longer form

 
M[ 2, 1 ] += a;
M[ 2, 2 ] += a;
M[ 2, 3 ] += a;
M[ 2, 4 ] += a;

You can also directly add a 2-dimensional matrix to all sub-matrices of a 3-dimensional matrix, or, generally, you can add a n-dimensional matrix to all n-dimensional sub-matrices of a m-dimensional matrix, given that m is larger than n and that the ranks of the sub-matrices are identical, by just writing them as if they were simple numbers. The same holds for all the other types of arithmetic operations. In all cases fsc2 will automatically try to get it right and spare you from having to write all kinds of loops to get the same effect.

You can also mix objects of different ranks in an expression: if M is, for example, a 3-dimensional matrix, N is a 2-dimensional matrix and R an 1-dimensional array you can write

 
M += N - R * 3;

In this case each element of R will first be multiplied by 3 and the resulting array is then subtracted from each of the sub-arrays of N. Finally, N is added to each of the sub-matrices of M.

Further, the built-in arithmetic functions can (as far as this makes any sense) be applied to arrays and matrices. In every case the function is applied to each element of the array or matrix, thus the result is another array or matrix of the same rank with its elements being the results of applying the function to each of the input array elements. For example, again using the array a defined above, applying the sqrt() function results in:

 
  sqrt( a )  ->   { 0.7071068, 1.0, 1.1414215 }

Finally, for obvious reasons, when computed assignments are used (i.e. `+=', `-=', `*=', `/=', `%=' or `^=') the left hand side variable of an equation has to be an array when arithmetic with arrays is used.


Back: 4.7.2 Operator precedence Forward: 4.8 Conditional operator   FastBack: 4. EDL Up: 4.7 Arithmetic FastForward: 5. Built-in Functions

This document was generated by Jens Thoms Toerring on September 6, 2017 using texi2html 1.82.