10 Arithmetic

 10.1 Integer
 10.2 Logical
 10.3 Floating Point
 10.4 Intrinsic Functions

10.1 Integer

You may include integer arithmetic in your scripts. First you must assign a value to each variable used with the set command.

       set count = 1
       set data = (10 24 30 17)
       set exception = -999
       set list

Notice that arrays are defined as spaced-separated values in parentheses. So $data[3] is 30. You can also set a variable to a null value, such as list above, so that the variable is ready to be assigned to an expression.

To perform arithmetic the expression is prefixed with the special @ character like this.

       @ count = $count + 1
       @ count++

Both of these add one to the value of count. Note that the space following the @ and around the = and + operator are needed. Likewise the examples below both subtract one from the value of count.

      @ count = $count - 1
      @ count--

There are several other operators, the most important ones are illustrated below.

       @ ratio = $count / 5
       @ octrem = $data[2] % 8
       @ numelement = $i * $j

The first divides the value of count by 5, rounding down, so if count was 11, ratio would be 2. The second assigns the remainder of the second element of the array called data after division by 8. So if data[2] is 30, octrem would be set to 6. Finally numelement is equated to the product of variables i and j.

The precedence order is * / %   followed by + -. If you are in doubt, use parentheses to achieve the desired order.

10.2 Logical

As variables are either integers or strings, you have to find an alternative route to have logical variables in your script. One way is to define string values "true" and "false" (or uppercase equivalents) and test for these. For instance, this checks the value of variable smooth; when it is true the current dataset is Gaussian smoothed.

       if ( $smooth == "true" ) then
          gausmooth \\
       end

Remember that UNIX is case sensitive, so for instance, TRUE and true are not the same.

Another popular way is to use an integer, which is assigned to 0 for a false value, and 1 for

true. Indeed this is the way logical expressions are evaluated by the shell. For instance in the following logical expression

       @ x = ($n < 5 || 20 <= $n)
       @ y = ( !($n < 5 || 20 <= $n) )

variable x is 0 (false) when n lies between 5 and 19 inclusive, but is 1 (true) otherwise. Variable y is the negation of x. Note the parentheses surrounding the logical expressions; they are needed when an expression contains >, <, |, or &. A list of the comparison operators is given in the table to the right.

Here are a few more examples.

   



Comparison operators


Operator Meaning


== Equal to
! Boolean NOT
!= Not equal
&& Boolean AND
|| Boolean OR
> Greater than
< Less than
>= Greater or equal to
<= Less than or equal to


       @ flag = ( $name != "abc" )
       @ integrate = ( $flux[4] > 20 && $band != 5 )
       @ finish = ( $finish && ( $count > $number || $flag == 0 ) )

The additional parentheses in the expression for finish indicate the evaluation order starting from the innermost parentheses.

Observant readers will have noticed there are no comparisons involving floating-point numbers. Although you can do some limited string comparison, another means is needed. One such is to use the bc calculator.

       @ bound = ‘echo "if ( $lower > -0.5 && $upper < 0.5 ) 1" | bc‘
  
       set current = 1.234*10^03
       set upper = 1234.56
       while ( ‘echo "if ( $current <= $upper) 1" | bc‘ )
           <statements when $current <= 1234.56>
       end
  
       if ( ‘echo "if ( ${asp} <= 1.1 ) 1" | bc‘ ) then
           <statements when $asp is less than or equal to 1.1>
       end
  

The " quoted if statement involving the desired conditional statements is passed to bc. If bc evaluates the statement true, it returns the 1, which is equivalent to true in C-shell. Note since the piping into bc is a command, the whole assignment is enclosed in backquotes. In the first example above, the parentheses are not required, as the > and < are part of a string, not operators, as far as the shell is concerned. The other two examples show this technique in the context of a loop control and an if …then block.

Note bc uses an arbitrary and controllable precision (cf. the length and scale attributes). Be aware it also uses a non-standard syntax for scientific notation, as seen defining variable current above.

The C-shell also offers some operators that test the characteristics of a file, such as file existence. See Section 12.4 for details.

10.3 Floating Point

The shell cannot perform non-integer arithmetic. Thus you need to employ some other utility. The standard UNIX bc arbitrary-precision calculator is one. You can also define an algebraic calculator with awk or gawk as shown below.

       alias acalc ’       awk "BEGIN{ print \!* }" ’
  
       set z = ‘acalc (sqrt(3.2)+exp(5.4))*4.1/5.2‘
       set circle_area = ‘acalc atan2(0,-1)*${rad}*${rad}‘

It is inadvisable to name the alias calc for reasons that will soon be evident. Note that in expressions you don’t escape the multiplication sign and the expression is not in " quotes. The small set of about ten mathemetical functions available in awk, including arctangent shown above that evaluates π, limits what you can achieve. Another option is the (SUN/95) calc command. calc has most of the Fortran intrinsic functions available. For the remainder of this section, we shall just deal with calc.

The calc tool evaluates Fortran-like expressions, sending the result to standard output. So suppose that we wish to add two real values.

       set a = 5.4321
       set b = 1.2345
       set c = ‘calc $a+$b‘

The variable c takes the value of adding variables a and b. Note the back quotes that cause calc to be executed.

This is fine if you know that the values will always be positive. However, calc will object if there are adjacent mathematical operators, such as +- as would happen if b were negative. So surround variables in parentheses, remembering that the ( ) are metacharacters. See Section 7.4 for more details.

Let’s redo the first example along with a few more to illustrate the recommended syntax. This time we’ll specify the expression by parameter name rather than position.

       set a = 5.4321
       set b = -1.2345
       set c = ‘calc exp="($a)+($b)"‘                     # c = 4.1976
       set d = ‘calc exp="’( $a - 0.5 * ($b) ) / 100 ’"‘  # d = 0.0481485
       set e = ‘calc exp="(($a)+($b))**3"‘                # e = 296.2874
       set f = ‘calc exp="’($a + ($b)) ** 3’"‘            # f = e

Don’t be intimidated by the surfeit of quotes. The " " are needed because we want the dollar to retain its variable-substitution meaning. If the expression contains embedded spaces (usually for clarity) it should be enclosed in single quotes as shown in the assignment to variable f. So in general the recipe for using calc is

     set variable = ‘calc exp="’expression’"‘

Don’t try to escape all the metacharacters individually because it can soon become very messy, error prone, and hard to follow.

The default precision is single precision. If you need more significant figures then append prec=_double to the calc command line. The special symbol pi has the value of π. So

       set arc = 0.541209
       set darc = ‘calc exp=$arc*180.0/pi prec=_double‘

converts an angle 0.541209 radians (stored in arc) to degrees using double-precision arithmetic.

It is sometimes easier to assemble the expression in another variable. Here’s another recipe which demonstrates this approach. Suppose that you want to find the average median value for a series of NDFs.

       # Estimates the median of each sky frame and subtracts it from that image
  
       # Enable KAPPA commands.  Initialise variables.
       kappa > /dev/null
       set first = 0
       set numndf = 0
  
       # Loop for all NDFs
       foreach file (*_fl.sdf)
  
       # Obtain the NDF’s name.
          set file1 = $file:r
  
       # Assign the median value of the frame.  HISTAT computes the median,
       # and PARGET extracts it from HISTAT’s MEDIAN output parameter.
       # Dispose of the HISTAT text output to the null file.
          histat $file1 \\ > /dev/null
          set median = ‘parget median histat‘
  
       # Subtract the median from the input NDF.
          csub $file1 $median  $file1"_m"
  
       # Count the number of NDFs.
          @ numndf = $numndf + 1
  
       # Form the string to sum the median values using CALC.  The shell
       # only permits integer arithmetic.  The expression is different
       # for the first file.
          if ( $first == 0 ) then
             set expr = "( "$median
             set first = 1
  
       # Append a plus sign and the next median value.
          else
             set expr = ‘echo $expr" + "$median‘
          endif
  
       end
  
       # Complete the expression for evaluating the average of the frame
       # medians.
       set expr = ‘echo $expr" ) / " $numndf‘
  
       # Evaluate the expression and report the result.
       echo "Average median is "‘calc $expr‘

The script builds an expression to evaluate the average of the median values. So the first time it has to write the left parenthesis and first median value into string variable expr, but otherwise each new value is appended to the expression. Once all the medians are evaluated, the remainder of the expression, including division by the number of NDFs is appended. Finally, the expression is evaluated using calc. If you want to learn more about the set median = ‘parget median histat‘ command see Section 9.2.

10.4 Intrinsic Functions

If you want to include intrinsic functions, such as logarithms and trigonometric functions in your calculations, or perhaps you need some function for an integer expression that is not supplied by the C-shell, such as finding the maximum or the absolute value, calc may be the solution. It offers the 28 functions tabulated below.

Here are a few examples.

       set a = 5
       set b = (3 4 6 -2)
       set c = ‘calc exp="’min( $a, $b[1], $b[2], $b[3] )’"‘
       set d = ‘calc exp="’dim( $b[4], $a ) + dim( $b[3], $a )’"‘

The first expression finds the minimum of the four integers, namely 3 and assigns it to variable c. The second expression sums two positive differences: 0 and 1 respectively.

       set mag = ‘calc exp="’-2.5 * LOG10( $counts )’"‘
       set separation = ‘calc exp="atand2(35.3,$dist)"‘
       echo The nearest index is ‘calc exp="nint($x+0.5)"‘

Variable mag is the magnitude derived from the flux stored in variable counts. separation is assigned the inverse tangent of 35.3 divided by the value of variable dist measured between 180 and 180 degrees.




Function Number of arguments Description



SQRT 1 square root: arg
LOG 1 natural logarithm: ln(arg)
LOG10 1 common logarithm: log 10(arg)
EXP 1 exponential: exp(arg)
ABS 1 absolute (positive) value: arg
NINT 1 nearest integer value to arg
MAX 2 or more maximum of arguments
MIN 2 or more minimum of arguments
DIM 2 Fortran DIM (positive difference) function
MOD 2 Fortran MOD (remainder) function
SIGN 2 Fortran SIGN (transfer of sign) function
SIN* 1 sine function: sin(arg)
COS* 1 cosine function: cos(arg)
TAN* 1 tangent function: tan(arg)
ASIN* 1 inverse sine function: sin 1(arg)
ACOS* 1 inverse cosine function: cos 1(arg)
ATAN* 1 inverse tangent function: tan 1(arg)
ATAN2* 2 inverse tangent function: tan 1(arg1/arg2)
SINH* 1 hyperbolic sine function: sinh(arg)
COSH* 1 hyperbolic cosine function: cosh(arg)
TANH* 1 hyperbolic tangent function: tanh(arg)
SIND* 1 sine function: sin(arg)
COSD* 1 cosine function: cos(arg)
TAND* 1 tangent function: tan(arg)
ASIND* 1 inverse sine function: sin 1(arg)
ACOSD* 1 inverse cosine function: cos 1(arg)
ATAND* 1 inverse tangent function: tan 1(arg)
ATAN2D* 2 inverse tangent function: tan 1(arg1/arg2)
*Function does not support integer arithmetic.



The intrinsic functions recognised by calc (adapted from SUN/61). The angular arguments/results of the trigonometric functions are in radians, except those suffixed with a D, which are in degrees.