Loosely speaking, an operator is a function, usually
attached to basic arithmetic operations, whose name contains only
non-alphanumeric characters. For instance `+`

or `-`

, but also
` = `

or ` += `

, or even `[ ]`

(the selection operator). As all
functions, operators take arguments, and return a value; *assignment*
operators also have side effects: besides returning a value, they change the
value of some variable.

Each operator has a fixed and unchangeable priority, which means that, in a given expression, the operations with the highest priority is performed first. Unless mentioned otherwise, operators at the same priority level are left-associative (performed from left to right), unless they are assignments, in which case they are right-associative. Anything enclosed between parenthesis is considered a complete subexpression, and is resolved recursively, independently of the surrounding context. For instance,

a + b + c --> (a + b) + c \\ left-associative a = b = c --> a = (b = c) \\ right-associative

Assuming that *op*_{1}, *op*_{2}, *op*_{3} are
binary operators with increasing priorities (think of `+`

,
`*`

, `^`

),
x *op*_{1} y *op*_{2} z *op*_{2} x *op*_{3} y is
equivalent to x *op*_{1} ((y *op*_{2} z) *op*_{2}
(x *op*_{3} y)).

GP contains many different operators, either unary (having only
one argument) or binary, plus a few special selection operators. Unary
operators are defined as either *prefix* or *postfix*, meaning
that they respectively precede (*op* x) and follow (x *op*) their
single argument. Some symbols are syntactically correct in both positions,
like `!`

, but then represent different operators: the `!`

symbol
represents the negation and factorial operators when in prefix and postfix
position respectively. Binary operators all use the (infix) syntax
x *op* y.

Most operators are standard (`+`

, `%`

, ` = `

), some are
borrowed from the C language (`++`

, ` << `

), and a few are
specific to GP (`\`

, `#`

). Beware that some GP operators differ
slightly from their C counterparts. For instance, GP's postfix `++`

returns the *new* value, like the prefix `++`

of C, and the binary
shifts ` << `

, ` >> `

have a priority which is different from (higher
than) that of their C counterparts. When in doubt, just surround everything
by parentheses; besides, your code will be more legible.

Here is the list of available operators, ordered by decreasing
priority, binary and left-associative unless mentioned otherwise. An
expression is an *lvalue* if something can be assigned to it. (The name
comes from left-value, to the left of a ` = `

operator; e.g.
`x`

, or `v[1]`

are lvalues, but `x + 1`

is not.)

***** Priority 14

`:`

as in `x:small`

, is used to indicate to the GP2C compiler that the
variable on the left-hand side always contains objects of the type specified
on the right hand-side (here, a small integer) in order to produce more
efficient or more readable C code. This is ignored by GP.

***** Priority 13
`( )`

is the function call operator. If f is a closure and *args*
is a comma-separated list of arguments (possibly empty),
f`(`

evaluates f on those arguments.*args*)

***** Priority 12

`++`

and `--`

(unary, postfix): if x is an `lvalue`

,
`x++`

assigns the value x+1 to x, then returns the new value of
x. This corresponds to the C statement `++x`

: there is no prefix
`++`

operator in GP. `x--`

does the same with x-1. These
operators are not associative, i.e. `x++++`

is invalid, since
`x++`

is not an lvalue.

***** Priority 11

`.`

*member* (unary, postfix): `x.`

extracts
*member**member* from structure x (see Section se:member).

`[ ]`

is the selection operator. `x[i]`

returns the i-th
component of vector x; `x[i,j]`

, `x[,j]`

and
`x[i,]`

respectively return the entry of coordinates (i,j), the
j-th column, and the i-th row of matrix x. If the assignment operator
(` = `

) immediately follows a sequence of selections, it assigns its right
hand side to the selected component. E.g `x[1][1] = 0`

is valid; but
beware that `(x[1])[1] = 0`

is not (because the parentheses force the
complete evaluation of `x[1]`

, and the result is not modifiable).

***** Priority 10

`'`

(unary, postfix): derivative with respect to the main variable.
If f is a function (`t_CLOSURE`

), f' is allowed and defines a new
function, which will perform numerical derivation when evaluated
at a scalar x; this is defined as (f(x+ϵ) - f(x-ϵ)) /
2ϵ for a suitably small epsilon depending on current precision.

? (x^2 + y*x + y^2)' \\ derive with respect to main variable`x`

%1 = 2*x + y ? SIN = cos' %2 = cos' ? SIN(Pi/6) \\ numerical derivation %3 = -0.5000000000000000000000000000 ? cos'(Pi/6) \\ works directly: no need for intermediate`SIN`

%4 = -0.5000000000000000000000000000

`~`

(unary, postfix): vector/matrix transpose.

`!`

(unary, postfix): factorial. x`!`

= x(x-1)...1.

`!`

(unary, prefix): logical *not*. `!x`

returns 1 if x is
equal to 0 (specifically, if `gequal0(x) == 1`

), and 0 otherwise.

***** Priority 9

`#`

(unary, prefix): cardinality; `#x`

returns `length(x)`

.

***** Priority 8

`^`

: powering. This operator is right associative:
`2^3^4`

is understood as `2^(3^4)`

.

***** Priority 7

`+`

, `-`

(unary, prefix): `-`

toggles the sign of its argument,
`+`

has no effect whatsoever.

***** Priority 6

`*`

: multiplication.

`/`

: exact division (`3/2`

yields 3/2, not 1.5).

`\`

, `%`

: Euclidean quotient and remainder, i.e. if x =
qy + r, then `x `

= q, `\ `

y`x%y`

= r. If x and y
are scalars, then q is an integer and r satisfies 0 ≤ r < |y|; if x
and y are polynomials, then q and r are polynomials such that deg r <
deg y and the leading terms of r and x have the same sign.

`\/`

: rounded Euclidean quotient for integers (rounded towards
+ oo when the exact quotient would be a half-integer).

` << `

, ` >> `

: left and right binary shift. By definition,
`x << n`

= x * 2^n if n > 0, and `truncate`

(x 2^{-n}) otherwise.
Right shift is defined by `x >> n`

= `x << (-n)`

.

***** Priority 5

`+`

, `-`

: addition/subtraction.

***** Priority 4

` < `

, ` > `

, ` <= `

, ` >= `

: the usual comparison operators,
returning 1 for `true`

and 0 for `false`

. For instance,
`x <= 1`

returns 1 if x ≤ 1 and 0 otherwise.

` <> `

, ` != `

: test for (exact) inequality.

` == `

: test for (exact) equality. `t_QFR`

having the same coefficients
but a different distance component are tested as equal.

` === `

: test whether two objects are identical component-wise. This is
stricter than ` == `

: for instance, the integer 0, a 0 polynomial or a
vector with 0 entries, are all tested equal by ` == `

, but they are not
identical.

***** Priority 3

`&&`

: logical *and*.

`||`

: logical (inclusive) *or*. Any sequence of logical
*or* and *and* operations is evaluated from left to right,
and aborted as soon as the final truth value is known. Thus, for instance,

x == 0 || test(1/x)

will never produce an error since `test(1/x)`

is not even evaluated
when the first test is true (hence the final truth value is true). Similarly

type(p) == "t_INT" && isprime(p)

does not evaluate `isprime(p)`

if `p`

is not an integer.

***** Priority 2

` = `

(assignment, *lvalue* ` = `

*expr*). The result of
`x = y`

is the value of the expression y, which is also assigned to
the variable `x`

. This assignment operator is right-associative. This is
*not* the equality test operator; a statement like `x = 1`

is always
true (i.e. non-zero), and sets `x`

to 1; the equality test would be
`x == 1`

. The right hand side of the assignment operator is evaluated
before the left hand side.

It is crucial that the left hand-side be an *lvalue* there, it avoids
ambiguities in expressions like `1 + x = 1`

. The latter evaluates as
`1 + (x = 1)`

, not as `(1 + x) = 1`

, even though the priority of
` = `

is lower than the priority of `+`

: `1 + x`

is not an lvalue.

If the expression cannot be parsed in a way where the left hand side is an lvalue, raise an error.

? x + 1 = 1 *** syntax error, unexpected '=', expecting $end or ';': x+1=1 *** ^--

Assignment to all variables is a deep copy: after x = y, modifying a
component of y will *not* change x. To globals it is a full copy to
the heap. Space used by local objects in local variables is released when
they go out of scope or when the value changes in local scope. Assigning a
value to a vector or matrix entry allocates room for that entry only (on the
heap).

, where *op* = *op* is any binary operator
among `+`

, `-`

, `*`

, `%`

, `/`

, `\`

, `\/`

,
` << `

, or
` >> `

(composed assignment *lvalue* *op*` = `

*expr*).
The expression `x `

assigns (*op* = y`x`

*op* y)
to `x`

, and returns the new value of `x`

. The result is *not*
an *lvalue*; thus

(x += 2) = 3

is invalid. These assignment operators are right-associative:

? x = 'x; x += x *= 2 %1 = 3*x

***** Priority 1
`- > `

(function definition): `(`

returns a
function object, of type *vars*)- > *expr*`t_CLOSURE`

.

**Remark.** Use the *op*` = `

operators as often as possible
since they make complex assignments more legible. Compare

v[i+j-1] = v[i+j-1] + 1 --> v[i+j-1]++ M[i,i+j] = M[i,i+j] * 2 --> M[i,i+j] *= 2

**Remark about efficiency.** the operators `++`

and `--`

are usually a little more efficient than their expended
counterpart:

? N = 10^7; ? i = 0; for(k = 1, N, i=i+1) time = 949 ms. ? i = 0; for(k = 1, N, i++) time = 933 ms.

On the other hand, this is not the case for the
*op*` = `

operators which may even be a little less efficient:

? i = 0; for(k = 1, N, i=i+10) time = 949 ms. ? i = 0; for(k = 1, N, i+=10) time = 1,064 ms.