Consider the following expression:
a - b c - d
If the addition and subtraction operators have the same level of precedence, as they do in programming languages, the precedence rules say nothing about the order of evaluation of the operators in this expression.
When an expression contains two adjacent 2 occurrences of operators with the same level of precedence, the question of which operator is evaluated first is answered by the associativity rules of the language. An operator can have either left or right associativity, meaning that when there are two adjacent operators with the same precedence, the left operator is evaluated first or the right operator is evaluated first, respectively.
Associativity in common languages is left to right, except that the exponentiation operator (when provided) sometimes associates right to left. In the Java expression
a - b c
the left operator is evaluated first.
Exponentiation in Fortran and Ruby is right associative, so in the expression
A ** B ** C
the right operator is evaluated first.
In Ada, exponentiation is nonassociative, which means that the expression
A ** B ** C
is illegal. Such an expression must be parenthesized to show the desired order, as in either
(A ** B) ** C
A ** (B ** C)
In Visual Basic, the exponentiation operator, ^, is left associative. The associativity rules for a few common languages are given here:
The order of evaluation of operators in APL expressions is determined entirely by the associativity rule, which is right to left for all operators. For example, in the expression
A × B C
the addition operator is evaluated first, followed by the multiplication operator (* is the APL multiplication operator). If A were 3, B were 4, and C were 5, b then the value of this APL expression would be 27.
Many compilers for the common languages make use of the fact that some arithmetic operators are mathematically associative, meaning that the associativity rules have no impact on the value of an expression containing only those operators. For example, addition is mathematically associative, so in mathematics the value of the expression
A B C
does not depend on the order of operator evaluation. If floating-point operations for mathematically associative operations were also associative, the compiler could use this fact to perform some simple optimizations. Specifically, if the compiler is allowed to reorder the evaluation of operators, it may be able to produce slightly faster code for expression evaluation. Compilers commonly do these kinds of optimizations.
Unfortunately, in a computer, both floating-point representations and floating-point arithmetic operations are only approximations of their mathematical counterparts (because of size limitations). The fact that a mathematical operator is associative does not necessarily imply that the corresponding floating-point operation is associative. In fact, only if all the operands and intermediate results can be exactly represented in floating-point notation will the process be precisely associative. For example, there are pathological situations in which integer addition on a computer is not associative. For example, suppose that a program must evaluate the expression
A B C D
and that A and C are very large positive numbers, and B and D are negative numbers with very large absolute values. In this situation, adding B to A does not cause an overflow exception, but adding C to A does. Likewise, adding C to B does not cause overflow, but adding D to B does. Because of the limitations of computer arithmetic, addition is catastrophically nonassociative in this case. Therefore, if the compiler reorders these addition operations, it affects the value of the expression. This problem, of course, can be avoided by the programmer, assuming the approximate values of the variables are known. Theprogrammer can specify the expression in two parts,ensuring that overflow is avoided. However, this situation can arise in far more subtle ways, in which the programmer is less likely to notice the order dependence.