Expressions and operators


There are six numeric data types in NCL: double, float, long, integer, 
short, byte. The float type is the basic type for representing floating
point numbers; double will provide the same or more precision than float; 
integer is the basic type for representing integral values; short will 
have the same or less precision as integer; byte will almost always be 
an 8-bit quantity. The algebraic operators operate on the numeric data 
types.
The following table summarizes the non-numeric data types in NCL:
---------------------------------------------------------------- 
 Data type         Description
---------------------------------------------------------------- 
 character         Used to store a single character
 string            A finite sequence of characters
 logical           Can have one of two values: True or False
 graphic           References an instance of an HLU object
 file              References a disk file (returned by addfile)
---------------------------------------------------------------- 
For an expression to be evaluated correctly, it is often necessary to 
convert one of the basic data types into another. This processes is called 
"coercion" and it is often done automatically. For example, when a float 
is multiplied by an integer, the integer will be converted to a float, 
the multiplication performed, and a float calculated for the 
expression value. The following table shows how the type coercions 
are performed:
 Type             Coercible to
---------------------------------------------------------------- 
 character        string
---------------------------------------------------------------- 
 short            character
                  string
                  integer
                  long
                  logical
                  float
                  double
--------------------------------------------------------------- 
 integer          string
                  long
                  logical
                  float
                  double
---------------------------------------------------------------- 
 long             logical
                  string
                  float
                  double
---------------------------------------------------------------- 
 float            logical
                  string
                  double
---------------------------------------------------------------- 
All numeric data types, strings, characters, logical, and graphic types 
can be created using the "new"
statement. There are two types of new calls: one creates an 
array of data with a specific missing value assigned to each element; 
the other creates the array of data using the default missing value. 
The new function takes, as parameters, an array of dimension sizes, 
the type keyword to create, and (optionally) a missing value to assign 
to each element of the new data array. The following creates a 
three-dimensional float array: 
a = new((/5,6,7/),float)
The following is an example of how to assign a specific missing value. 
a = new((/5,6,7/),float,-1e12)
File data types are created differently. A file type is created only by 
the addfile function. Arrays of type graphic can be created with new, 
but none of the elements of the array will actually reference an existing 
HLU object. Each element will contain a missing value. In addition to 
new, there are ways of entering data manually. Currently there are four 
types of literal values. Floating point numbers must be entered with a 
decimal point. The following show creation of data using literal 
floating point values: 
a = 2.
a = 1.2
a = (/ 1., 2., 3. /)
Integer values are specified without the decimal point:
a = 2
a = (/ 1, 2, 3 /)
String values are specified as characters enclosed in double quotes ("): 
a = "NCAR Graphics"
Logical values are specified using the keywords "True" and "False":
a = False
The following table summarizes the primary operators in NCL. 
The operators are presented in their order of precedence, that is, in the 
evaluation of an expression, if one operator appears above another in 
the table, it will be performed first. See the
examples of expression evaluation 
below. If a 
non-associative 
operator (such as "^" or "%") occurs 
successively, then the precedence proceeds left-to-right. For 
example, 2^3^4 evaluates to 4096.
---------------------------------------------------------------- 
 Operator         Description                   Type
---------------------------------------------------------------- 
    ->            File variable                 metadata
---------------------------------------------------------------- 
    @             Attribute                     metadata
    &             Coordinate variable           metadata
    !             Dimension name                metadata
---------------------------------------------------------------- 
    -             Unary negation                algebraic
---------------------------------------------------------------- 
    ^             Exponentiation                algebraic
---------------------------------------------------------------- 
    *             Multiplication                algebraic
    /             Division                      algebraic
    %             Modulus                       algebraic
---------------------------------------------------------------- 
    +             Addition                      algebraic
    -             Subtraction                   algebraic
---------------------------------------------------------------- 
    <             Less than selector            algebraic
    >             Greater than selector         algebraic
---------------------------------------------------------------- 
  .not.           Logical negation              logical
  .le.            Less than or equal to         relational
  .lt.            Less than                     relational
  .ge.            Greater than or equal to      relational
  .gt.            Greater than                  relational
  .ne.            Not equal to                  relational
  .eq.            Equal to                      relational
  .and.           And                           logical
  .or.            Or                            logical
  .xor.           Exclusive or                  logical
---------------------------------------------------------------- 
   =              Assignment                    assignment
---------------------------------------------------------------- 
-  File variable (->)
 -  This operator requires two operands. The first operand is a 
     
     file variable (as created with an 
     addfile
     command). The second operand is a variable name. The specified 
     variable is either set or retrieved as appropriate. The file variable
    operator differs from other operators in that the operands are not expressions
	but identifiers.
     Examples:
       file1->a = 5
       file1->a@value = 22.
       print(file1->var1)
 -  Attribute (@)
 -  This operator takes two operands. The first operand is a 
     variable name, and the second operand is an 
     attribute
     name for the variable in the first operand. The result can be any type.
	The attribute operator is similar to the file variable operator in that
	its operands also must be identifiers and not expressions.
     Examples:
     a@units = "Degrees"
     a@value = 3.14159
     print(a@units)
 -  Coordinate variable (&)
 -  This operator requires two operands.  The first operand is a 
     variable name, and the second operand is the 
     
     name of a dimension of 
     the first operand.  The result is a 
     
     coordinate variable. The 
     values in the coordinate variable must be 
     
     monotonically increasing 
     or decreasing. If the value assigned is non-monotonic or contains 
     missing values, the assignment still occurs but a WARNING message 
     is generated and attempts to use coordinate subscripting will fail 
     with a FATAL message. The coordinate variable operator only 
     accepts identifiers just like  the attribute and file variable 
     operators.
     Example:
         a&Dimension1 = (/.1,.2,.3,.4,.5,.../)
 -  Dimension name (!)
 -  This operator takes two operands. The first operand is either a 
     
     variable or a 
     
     file variable, and the second operand is an integer. 
     The second operand indicates the dimension number (starting with 0). 
     The result is of type string. This operator is used to retrieve or 
     set names for a variable's dimension(s).
 -  Unary negation (-)
 -  This operator operates on a single operand and that operand must 
     have a numeric type. If the operand is an array, the negation will 
     be applied individually to each element of the array.
 -  Exponentiation (^)
 -  This operator requires two operands. The first operand is raised 
     to the power of the second operand. The operands must be of 
     numeric type. If the first operand is negative, then the second 
     operand must be positive. If either operand is a non-linear array, 
     then the other operand must be a scalar or an array of the same shape. 
     An array raised to a scalar power results in an array of the same 
     size with each element of the original array raised to the scalar 
     power. A scalar raised to an array power will result in array of 
     the same shape as the power where each element of the array is 
     the scalar raised to the power of the array element. An array raised 
     to an array power results in the obvious thing. The result of the 
     exponentiation operator is of type double.
 -  Multiplication (*)
 -  This operator requires two operands. The first operand is multiplied 
     by the second operand. The operands must be of numeric type. 
     Array operands are handled in a manner analogous to that described 
     in exponentiation.
 -  Division (/)
 -  This operator requires two operands. The first operand is divided 
     by the second operand. The operands must be of numeric type. If 
     both operands are of type integer, then the result will be an 
     integer where any decimal remainders are truncated. Array operands 
     are handled in a manner analogous to that described in exponentiation. 
 -  Modulus (%)
 -  This operator requires two operands of type integer. The result is 
     an integer type that is the integral remainder of dividing the 
     first operand by the second. Array operands are handled in a manner 
     analogous to that described for exponentiation.
 -  Addition (+)
 -  This operator requires two operands. The first operand is added to 
     the second operand. The operands must both be of numeric type or 
     both of string type. If both operands are of numeric type, then the 
     result will be the sum of the two operands; if both operands are 
     of string type, then the result will be the concatenation of the two 
     strings. Array operands are handled in a manner analogous to that 
     described for exponentiation.
 -  Subtraction (-)
 -  This operator requires two operands. The second operand is 
     subtracted from the first operand. The operands must both be of 
     numeric type. Array operands are handled in a manner analogous to 
     that described for exponentiation.
 -  Less than selector (<)
 -  This operator requires two operands. The result is the smaller of 
     the values in the first operand and the second operand. If one operand 
     is a scalar and the other is an array, then, for each array entry, 
     the smaller of the array element and the scalar is selected for each 
     element of the resultant array. The operands must either both be type 
     numeric, or both type string. For strings string1 and string2, 
     "string1 < string2" yields string1 if the first character of 
     string1 is less than the first character of string2 in the ASCII 
     collating sequence.
 -  Greater than selector (>)
 -  This operator requires two operands. The result is the larger of 
     the values in the first operand and the second operand. If one 
     operand is a scalar and the other is an array, then, for each 
     array entry, the larger of the array element and the scalar is 
     selected for each element of the resultant array. For strings 
     string1 and string2, "string1 > string2" yields string1 if 
     the first character of string1 is greater than the first character 
     of string2 in the ASCII collating sequence.
 -  Logical negation (.ne.)
 -  This operator requires a single logical operand and returns a 
     logical result. If the operand is True, then the result is False; 
     if the operand is False, then the result is True.
 -  Less than or equal to (.le.)
 -  This operator requires two operands of numeric type. The two operands 
     can be a scalar and an array, or two arrays of the same shape. 
     If a scalar is being compared to an array, then an array of 
     logical values is returned as per individual comparisons of the scalar 
     with each array element. If two arrays are being compared, 
     then an array of logical values is returned as per comparing 
     each of the elements in one array with those in the other.
 -  Less than (.lt.)
 -  This operator requires two operands of numeric type. The two 
     operands can be a scalar and an array, or two arrays of the same 
     shape. If a scalar is being compared to an array, then an array of 
     logical values is returned as per individual comparisons of the 
     scalar with each array element. If two arrays are being 
     compared, then an array of logical values is returned as per 
     comparing each of the elements in one array with those in the other.
 -  
     Greater than or equal to (.ge.)
 -  This operator requires two operands of numeric type. The two 
     operands can be a scalar and an array, or two arrays of the same 
     shape. If a scalar is being compared to an array, then an array of 
     logical values is returned as per individual comparisons of 
     the scalar with each array element. If two arrays are being 
     compared, then an array of logical values is returned as per 
     comparing each of the elements in one array with those in the other.
 -  Greater than (.gt.)
 -  This operator requires two operands of numeric type. The two operands 
     can be a scalar and an array, or two arrays of the same shape. If 
     a scalar is being compared to an array, then an array of logical 
     values is returned as per individual comparisons of the scalar 
     with each array element. If two arrays are being compared, then 
     an array of logical values is returned as per comparing each of 
     the elements in one array with those in the other.
 -  Not equal to (.ne.)
 -  This operator requires two operands of any type and returns a 
     result of type logical. If a scalar is being compared to an array, 
     then an array of logical values is returned as per individual 
     comparisons of the scalar with each array element. If two arrays 
     are being compared, then an array of logical values is returned as 
     per comparing each of the elements in one array with those in the other.
 -  Equal to (.eq.)
 -  This operator requires two operands of any type and returns a 
     result of type logical. If a scalar is being compared to an 
     array, then an array of logical values is returned as per individual 
     comparisons of the scalar with each array element. If two arrays are 
     being compared, then an array of logical values is returned as per 
     comparing each of the elements in one array with those in the other.
 -  And (.and.)
 -  This operator requires two operands of type logical and returns a 
     result of type logical. The result is True if and only if both 
     operands are True.
 -  Or (.or.)
 -  This operator requires two operands of type logical and returns 
     a result of type logical. The result is True if and only if 
     either of the operands is True.
 -  Exclusive or (.xor.)
 -  This operator requires two operands of type logical and returns 
     a result of type logical. The result is True if and only if one, 
     but not both, of the operands is True.
 -  Assignment (=)
 -  The operator requires two operands. The value of the second operand 
     is assigned to the first operand. The type of the second operand must 
     be coercible to the type of the first operand.
 
An NCL expression is any sequence of operators and operands that results 
in the computation of a value. In particular, any 
literal value is an 
expression, and any variable is an expression. Also, arrays are 
expressions as well as functions and procedures. Operators applied to 
expressions are expressions.
Parentheses surrounding an expression result in an expression and can be 
used to alter the order of evaluation in expressions in the same manner 
that they are used in most all programming languages. So, for example,
a + b / c
would be evaluated by dividing b by c and then adding a, whereas
(a + b)/ c
would be evaluated by adding b and a and then dividing by c.
Here are some examples of expressions:
.5
v1
sin(3.1415926)
a(2,3,1)^(b-1) + (file1->a)/2.718
String3 = "String1" + "String2"
(/2,8,11/) % (/2,3,4/)
((v1.lt.v3) .xor. (v2.lt.v4))
If a variable is created and no valid value has been assigned to that 
variable, then that variable will have an 
attribute named "_FillValue", 
and the value of the variable will be set to the value of "_FillValue".  
A pre-defined value of the same type as the variable will be assigned 
to "_FillValue" unless a value has been specifically assigned by the 
user. Consider the following NCL session:
ncl 0> a = new(2,float)
ncl 1> b = (/ 3., a(0) /)
ncl 2> print(b)
Variable: b
Type: float
Total Size: 8 bytes
            2 values
Number of Dimensions: 1
Dimensions and sizes:   [2]
Coordinates: 
(0)     3
(1)     -999
ncl 3> c = (/ 5., 8. /) + b
ncl 4> print(c)
Variable: c
Type: float
Total Size: 8 bytes
            2 values
Number of Dimensions: 1
Dimensions and sizes:   [2]
Coordinates: 
(0)     8
(1)     -991
The variable "a" is created using the new command and, since a has not 
been assigned any value, it receives the default _FillValue of -999. 
This value for a is used in the creation of b, and this becomes the 
actual value of the second element of b. This value is used in the 
computation of c.
If the variables making up an expression contain more than one 
"_FillValue" value, the _FillValue of the left-most variable that 
contains a missing value is used for the value of the expression.
The handling of 
metadata in the computation of expressions presents 
problems. For example, consider a case where one file named "east" 
contains a vector variable U and another file named "north" contains a 
vector variable V. Suppose U has an attribute "long_name" that is set 
to "east wind component" and V has an attribute called "long_name" that 
is set to "north wind component". Then, suppose we want to calculate the 
wind speed and store the result in a variable c:
c = sqrt(east->U^2 + north->V^2)
Clearly, neither of the values for the attribute "long_name" applies 
to c.  Similarly, attributes like valid_range, valid_min, valid_max, 
and scale_factor could not be correctly propagated to c. NCL solves 
this problem simply by not propagating metadata in the evaluation of an 
expression unless that expression is a single variable. This 
rule also applies to variables used as parameters to functions.
      
---------------------------------------------------------------- 
 Expression                    Evaluates as
---------------------------------------------------------------- 
 a < b + c                     a < (b + c)
 a/b*d%c                       ((a/b)*d) % c
 a^b*-c/d+e%f<g                ((((a^b)*(-c))/d) + (e % f)) < g
 a+b.lt.c*d                    (a+b) .lt. (c*d)
 a.le.c.or.d.gt.e.and.f.ne.g   (a.le.c).or.((d.gt.e).and.(f.ne.g))
 file2->a^3+file2->b*5         ((file2->a)^3) + ((file2->b)*5)
---------------------------------------------------------------- 
User Guide Control Panel
NG4.1 Home, Index, Examples, Glossary, Feedback, UG Contents, UG WhereAmI?
 $Revision: 1.9 $ $Date: 1998/06/15 22:08:54 $