Relational Operators

 

SPL includes a number of relational and logical operators and functions:

 

 

Operator

Function

Description

<

LESSER

less than

<=

LESSEREQ

less than or equal

>

GREATER

greater than

>=

GREATEREQ

greater than or equal

==

EQUAL

Equal

!=

NOTEQ

not equal

&&

AND

logical and

||

OR

logical or

!

NOT

logical not

 

XOR

exclusive or

%

MOD

Modulo

 

For example, the expression a != 10 is functionally equivalent to noteq(a, 10).

Relational and logical operators return a binary result (1 or 0) for scalar parameters. For example:

 

a = 1;

a < 10; returns: 1

a != 1; returns: 0

 

Here are two functions that determine whether a number is even or odd:

 

/* returns 1 if number is even, else 0 */

iseven(x)

{

     return(2*(int(x/2)) == x);

}

 

 

/* returns 1 if number is odd, else 0 */

isodd(x)

{

     return(not(iseven(x)));

}

 

The built-in INT function returns the integer part of a number. The % operator could also be used to detect an even or odd number.

 

/* returns 1 if number is even, else 0 */

iseven(x)

{

    return(x % 2 == 0);

}

 

 

/* returns 1 if number is odd, else 0 */

isodd(x)

{

    return(x % 2 != 0);

}

 

 

A function that returns the sign of a number is quite straightforward:

 

/*

 *  returns the sign of a number,

 *  1: positive, 0: zero, -1: negative

 */

 

sgn(n)

{

    local sign;

    

    sign = (n > 0) - (n < 0);

 

    return(sign);

 }

 

Relational and logical operators also work on entire series, returning a binary series (a series consisting of 1's or 0's) as the result.

 

s = {1, 2, 3, 4};

t = s >= 2;

 

The series t contains the values {0, 1, 1, 1}. This feature results in very powerful and compact SPL code. Consider the function:

 

/* replace series values based on logical condition */

replace(s, cond, val)

{

    local result;

 

    result = s * not(cond) + val * cond;

 

    return(result);

}

 

Now replace(w1, w1 > 10, 11) replaces all the values in W1 that exceed 10.0 with the value 11.0. The expression replace(w1, w1 < w2, w2) creates a series that contains the larger of the values of W1 and W2 on a point by point basis. Notice again that traditional looping is not required.

 

As a related example, the following function returns the indices of the non-zero elements of a series or array.

 

/* return indices of non-zero elements of an array */

findnz(x)
{
    local len, ncol, nz, ind, rowind;
 
    (len, ncol) = size(x);
 
    /* length for indices */
    num = len * ncol;
 
    /* get non-zero values */
    nz = (unravel(x) != 0.0);
 
    /* generate indices */
    ind = 1..num;
 
    /*
     *  get indices by multiplying and
     *  removing the zero elements
     */
 
    rowind = nz * ind;
    rowind = delete(rowind, rowind == 0.0);
 
    return(rowind);
}

 

The SIZE function returns the number of rows and columns of an array. By exploiting the series processing feature of SPL, the series nz is 1 where the input is non-zero and 0 where the input is zero. Multiplying nv by a linear ramp of slope 1 and then removing the zero elements produces a series that contains the indices of the non-zero elements of the input. For example:

 

a = {1, 0, 5};

b = findnz(a);

c = findnz(a > 1);

d = a[b];

 

b == {1, 3}

c == {3}

d == {1, 5}

 

The built-in FIND function returns the indices of the non-zero elements of array as a single "unraveled" series. These indices can be used to address arrays.

 

a = {{1, 2, 3}, {4, 5, 2}, {2, 8, 9}};

b = find(a == 2);

c = a[b];

 

b == {3, 4, 8}

c == {2, 2, 2}

 

 

Short‑Circuit Conditionals

 

Short‑circuit (minimal) evaluation is the default behavior of the conditional operators || (logical OR) and && (logical AND). Consider the expressions:

 

c = a || b;

f = d && e;

 

The second argument is evaluated only when the result of the conditional cannot be determined from the first argument alone.

 

 

Short‑circuit evaluation is useful for avoiding unnecessary computation. For example:

 

c = (max(w1) > 0) || (max(gnorm(1000000000, 1)) > 0)

 

If W1 contains only positive values, the first condition is true and the expensive random‑number computation in the second argument is skipped. This behavior is equivalent to:

 

if (max(w1) > 0)

{

    c = 1;

}

else

{

    c = max(gnorm(1000000000, 1)) > 0;

}

 

The SOR(a, b) and SAND(a, b) functions also perform short‑circuit conditional evaluation. In contrast, OR(a, b) and AND(a, b) use eager evaluation, where both arguments are always evaluated.

 

If the configuration parameter SPL_SHORT_CIRCUIT is set to 0, the operators ||, &&, SOR, and sand revert to eager evaluation.