Rwb2 programmer instructions for binding


2.4 Expressions, operands and operators

Let's start with math expressions and then find out how to write it in Java. A mathematical formula, such as an expression, consists of operands and operators. An operand is a variable or a literal. In the case of a variable, the value is read from the variable and the calculation is carried out with it.

The types of operators

The operators link the operands. Depending on the number of operands, we differentiate between the following types of operators:

  • If an operator is defined on exactly one operand, it is called a unary operator (or a one-digit operator). The minus (negative sign) in front of an operand is a unary operator because it applies to exactly the following operand.

  • The common plus, minus, times, and divided operators are binary (two-digit) operators.

  • There is also a three-digit question mark operator for conditional expressions.

Operators allow individual expressions to be combined to form new expressions. Some operators are known from school, such as addition, comparison, assignment and others. C (++) programmers will recognize many friends.


2.4.1 Assignment operator

In Java, the equal sign is used for assignment. [75] (Although the assignments look like mathematical equations, there is one important difference: the formula cannot be fulfilled mathematically - at least in the decimal system without additional algebra there cannot be one that satisfies. From a programming point of view, it's okay because the variable is incremented by one.) The assignment operator is a binary operator with the variable to be assigned on the left and an expression on the right.

[eg] example

An expression with assignments:

The multiplication calculates the product of 12 and 2 and stores the result in. The value of all primitive variables that occur in the expression is read out and inserted into the expression. [76] (There are programming languages ​​in which value operations are specially marked, for example in LOGO. A value operation is written there with a colon in front of the variable, for example.) This is also called a value operation, since the value of the variable is considered and not its storage location or even its variable name.

The assignment operator only copies the result into the variable after the expression has been evaluated. If there are runtime errors, for example due to division by zero, there is no write access to the variable.

Assignments are also expressions

Assignments can often be found as expression instructions, but they can appear at any point where an expression is permitted, for example in a method call such as:

int a = 1; // declaration with initialization
a = 2; // statement with assignment
System.out.println (a = 3); // expression with assignment. Returns 3.

Language comparison

The single equal sign is only used for assignment in Java. In other programming languages ​​the assignment is made clear by a different symbol, as in Pascal with. In order to be able to separate assignments from comparisons, Java defines a binary comparison operator here, following the C (++) tradition. The comparison operator always returns the result type:

int baba = 1;
System.out.println (baba == 1); // "true": expression with comparison
System.out.println (baba = 2); // "2": Expression with assignment

Multiple assignments in one step

Assignments of the form are allowed and have the same meaning as the three statements. The explicit brackets make it clear once again that assignments can be nested and assignments are like expressions that return a value. But even if we think that

a cool simplification compared to

is, we should get by with one assignment per line.

The order of the evaluation clearly shows the following example:

int b = 10;
System.out.println ((b = 20) * b); // 400
System.out.println (b); // 20

2.4.2Arithmetic operators

An arithmetic operator links the operands with the operators addition (), subtraction (-), multiplication () and division (). There is also the remainder operator (), which takes into account the remainder that remains after the division. All operators are defined for integer values ​​as well as for floating point numbers. The arithmetic operators are binary, and on the left and right the types are numeric. The result type is also numeric.

Numerical conversion

In the case of expressions with different numeric data types, such as and, the compiler converts all operands to the more comprehensive type before applying the operation. Before evaluating, the integer is converted into an and then the addition is carried out - the result is also of the type. This is called numeric promotion. With and the special rule applies that they are converted into before. [77] (http://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.6.1) ( Also in Java bytecode there are no arithmetic operations on, and.) Then the operation is carried out and the result type corresponds to the broader type.

The division operator

The binary operator forms the quotient from dividend and divisor. The dividend is on the left and the divisor on the right. The division is defined for integers and for floating point numbers. The integer division rounds to zero and the result is not a floating point number, so the result is and not 0.333 ... The data type of the result is determined by the operands and not the operator. If the result is to be of the type, an operand must also be.

System.out.println (1.0 / 3); // 0.3333333333333333
System.out.println (1 / 3.0); // 0.3333333333333333
System.out.println (1/3); // 0

Penalty for division by zero

School mathematics already taught us that division by zero is not allowed. If we carry out an integer division in Java with the divisor 0, Java punishes us with one which, if not dealt with, leads to the end of the program flow. With floating point numbers, division by 0 does not produce an exception, but +/- infinite and with the special value (more on this follows in Chapter 22, "Bits and Bytes and Mathematics"). A stands for Not a Number (also sometimes called "Unnumber") and is generated by the processor if it cannot perform a mathematical operation such as division by zero.

anecdote

On the guided missile cruiser USS Yorktown, a crew member accidentally entered the number zero. This resulted in a division by zero, and the error propagated so far that the software crashed and the drive system stopped. The ship drifted in the water without propulsion for several hours.

The remainder operator% *

An integer division doesn't necessarily have to go smoothly, as in the case of 9/2. In this case there is the remainder 1. This remainder is provided by the remainder operator, often also called modulo. [78] (Mathematicians differentiate between the two terms remainder and modulo, since a modulo is not negative, the remainder in Java it is. But we shouldn't care.)

System.out.println (9% 2); // 1

The remainder operator also applies to floating point numbers, and the operands can be negative.

System.out.println (12.0% 2.5); // 2.0

The division and the remainder are based on a simple formula in Java:

(int) (a / b) × b + (a% b) = a

[eg] example

The equation is true if we choose around and. The following applies: and results. Then surrender.

From this equation it follows that the result of the residual value is only negative if the dividend is negative; it is only positive if the dividend is positive. It is easy to see that the result of the remainder operation is always really smaller than the value of the divisor. We have the same case as with the integer division, that a divisor with the value 0 triggers one and leads to the result with floating point numbers.

Listing 2.11 RemainderAndDivDemo.java, main ()

System.out.println ("+ 5% +3 =" + (+ 5% +3)); // 2
System.out.println ("+5 / +3 =" + (+5 / +3)); // 1

System.out.println ("+ 5% -3 =" + (+ 5% -3)); // 2
System.out.println ("+5 / -3 =" + (+5 / -3)); // -1

System.out.println ("-5% +3 =" + (-5% +3)); // -2
System.out.println ("-5 / +3 =" + (-5 / +3)); // -1

System.out.println ("-5% -3 =" + (-5% -3)); // -2
System.out.println ("-5 / -3 =" + (-5 / -3)); // 1

It takes getting used to the fact that the first operand (dividend) defines the sign of the remainder and never the second (divisor). In Chapter 22, "Bits and Bytes and Math," we'll see a method that works slightly differently.

["]Note

In order to test with whether an odd number is, must be positive, because Java evaluates too. The test for odd numbers will only be correct again with.

Residual value for floating point numbers and Math.IEEEremainder () *

Using the above formula, we can easily calculate the result of a remainder operation even with floating point numbers. It must be ensured that the operator does not behave as under IEEE 754. Because this standard prescribes that the remainder operation calculates the remainder from a rounding division and not from a cutting one. The behavior would not be analogous to the residual value for integers. Java defines the remainder for floating point numbers just like the remainder for integers. If we want a residual value behavior as prescribed by IEEE 754, we can use the static library method [79] (There are also methods that do not begin with lowercase letters, although this is very rare and only occurs in special cases nice.) use.

Even with the remainder operation on floating point numbers, we will never expect an exception. Any errors are indicated as described in the IEEE standard. An overflow or underflow can occur, but it cannot be checked.

Rounding error *

In principle, instructions should result as always, but internal rounding errors occur in the display and make the result more and more inaccurate from calculation to calculation. A particularly unfavorable error occurred in 1994 with the Pentium processor in the division algorithm Radix-4 SRT, without the programmer being the culprit:

double x, y, z;
x = 4195835.0;
y = 3145727.0;
z = x - (x / y) * y;
System.out.println (z);

A faulty processor returns 256 here, although the calculation rule stipulates that the result must be 0. According to Intel, the error should only appear every 27,000 years for a normal user (gamer, software developer, surfer?). Lucky for most. A study by IBM calculated an error rate of once every 24 days. All in all, Intel took back the CPUs, lost over $ 400 million, and got its head out of the loop late.

Most rounding errors result from the fact that finite decimal fractions must be represented in the computer as approximate values ​​for periodic binary fractions. corresponds to a periodic mantissa in IEEE format.


2.4.3Unary minus and plus

The binary operators sit between two operands, while a unary operator takes exactly one operand. The unary minus (operator for sign reversal), for example, reverses the sign of the operand. A positive value becomes a negative and a negative value becomes a positive one.

[eg] example

Reverse the sign of a number:

An alternative is:

The unary plus is actually unnecessary; however, the developers introduced it for reasons of symmetry.

[eg] example

Minus and plus are directly in front of the operand, and the compiler knows for itself whether this is unary or binary. The compiler also recognizes the following construction:

This gives the value. The compiler does not recognize an expression like, however, since the connected minus signs are interpreted as an increment and not as a unary operator. So the separator, space in this case, is important.


2.4.4 Assignment with operation

In Java, assignments can be combined with numeric operators. For a binary operator (called symbolic) in the expression, the compound operator abbreviates the expression to. Here are a few examples:

Detailed notation

Notation with compound operator

Table 2.8 Written out variant and short notation with the compound operator

The following example shows that an assignment is always an expression:

int a = 0;
System.out.println (a); // 0
System.out.println (a + = 2); // 2
System.out.println (a); // 2

We should pay special attention to the automatic brackets. In the case of an expression such as, the dot-before-line rule applies and not of course.

If the right-hand side is a more complex expression, it will only be evaluated once. This is important for method calls that have side effects, such as changing states such as a counter.

[eg] example

We also benefit from compound operations when accessing arrays (see Section 3.8, "Arrays"), since the index is evaluated only once:

array [2 * i + j] = array [2 * i + j] + 1;

The following instruction is easier to read:


2.4.5 Prefix or postfix increment and decrement

The raising and lowering of variables is a very common operation, for which the developers in the previous C language also donated an operator. The practical operators and abbreviate the program lines for increment and decrement:

i ++; // Abbreviation for i = i + 1
j--; // j = j - 1

However, a local variable must be initialized beforehand, since read access takes place before write access. The / operator thus fulfills two tasks: In addition to returning the value, there is also a change in the variables.

["]Note

We also find the post-increment in the name of the programming language C ++. It is supposed to express that it is »C-with-one-on it«, i.e. an improved C. Knowing about the postfix operator makes it clear that this increase only occurs after use - so C ++ is also just C, and the benefit comes later. One of the developers of Java, Bill Joy, once described Java as C ++. He was referring to C ++ without the hard-to-maintain properties.

Before or after?

The two operators return an expression and therefore return a value. However, it makes a subtle difference where this operator is placed. It is available in two variants: It can appear in front of the variable, as in (prefix notation), or after it, as in (postfix notation). The prefix operator changes the variable before evaluating the expression, and the postfix operator changes it after evaluating the expression. In other words: If we use a prefix operator, the variable is first increased or decreased and then the value is returned.

[eg] example

Prefix / postfix in an output statement:

Prefix increment and decrement

Postfix increment and decrement









With the possibility of increasing and decreasing variables, there are four variants:

prefix

Postfix

Increment

Pre-increment,

Post increment,

Decrement

Pre-decrement,

Post decrement,

Table 2.9 Prefix and Postfix Increment and Decrement

["]Note

In Java, increment () and decrement () are allowed for all numeric data types, including floating point numbers:

double d = 12;
System.out.println (--d); // 11.0
double e = 12,456;
System.out.println (--e); // 11.456

Some curiosities *

Finally, we want to deal with a special feature of the post-increment and pre-increment that is not worth emulating:

int i = 1;
i = ++ i;
System.out.println (i); // 2
int j = 1;
j = j ++;
System.out.println (j); // 1

The first case is not surprising, because it increases the value 1 by 1, and then 2 is assigned to the variable. It is more sophisticated with: The value of is 1, and this value is recorded internally. Then the variable increases by 1. But the assignment is based on the noted value, which was 1. So is .

Language comparison: sequence points in C (++) *

The more freedom a compiler has, the more unabashedly it can optimize. A compiler is particularly interested in write access, because if it can save it, the program will run a little faster later. However, so that the result of a compiler remains manageable, the C (++) standard defines sequence points to which all write accesses have been clearly assigned (the fact that the compiler will make optimizations later is a different story; the sequence points belong to the semantic model, optimizations do not change that). The semicolon at the end of instructions forms a sequence point, for example. In an expression such as, the scramble access to must be resolved before a read access for the assignment to can be made.The problem is that there are not that many sequence points and it can happen that two ambiguous write accesses to the same variable take place between two sequence points. However, since this is undefined in C (++), the compiler can behave as it wants - it only has to behave as required at the sequence points. Problem cases are: or, because an increment / decrement is read / write access, also, which is nothing else than. Unfortunately, the assignment does not constitute a sequence point. With assignments of this type, everything can be in later, depending on what the compiler is executing at what point in time. In Java these things are clearly regulated by the specification, in C (++) it is only regulated that the behavior between the sequence points must be clear. But modern compilers recognize competing write accesses between two sequence points and warn them (with the appropriate warning level). [80] (With the GCC compiler, the switch (which is also taken with) onlinedocs / gcc / Warning-Options.html.)


2.4.6 The relational operators and the equality operators

Relational operators are comparison operators that compare expressions with one another and produce a truth value of the type. The operators provided by Java for numerical comparisons are:

  • greater ()

  • smaller ()

  • greater or equal ()

  • less than / equal to ()

There is also a special operator for testing reference properties.

There are also two comparison operators that Java calls equality operators:

  • Test for equality ()

  • Inequality test ()

The fact that Java makes a difference between equality operators and comparison operators here is due to a slightly different priority, which we should not concern ourselves with any further.

Like arithmetic operators, relational operators adapt their operands to a common type. If the types are reference types, only the comparison operators and are allowed.

Hardly any confusion problems with == and =

The use of the relational operator and the assignment often leads to problems for beginners, since mathematics only ever knows one equal sign for comparisons and assignments. Fortunately, the problem is not as severe in Java as it is in C (++), for example, because the types of operators are different. The comparison operator only ever gives the return value. However, assignments of numeric types result in a numeric type again. So there cannot be a problem like the following:

int a = 10, b = 11;
boolean result1 = (a = b); // Compiler error
boolean result2 = (a == b);

[eg] example

The truth variable should be when the sign is equal to the minus:

boolean hasSign = (sign == '-');

The order of evaluation is as follows: First the result of the comparison is calculated, and this truth value is then copied into.

(Anti) style

When comparing with, both operands can be swapped - if the two sides do not produce any influencing side effects, e.g. change states. Nothing changes in the result because the relational operator is commutative. So are

if (worldExpoShanghaiCostInUSD == 58000000000L)

and

if (58000000000L == worldExpoShanghaiCostInUSD)

semantically the same. In the case of an equality comparison between variable and literal, many developers with a past in the programming language C will set the constants on the left and the variable on the right. The reason for this so-called Yoda style [81] (Yoda is a character from Star Wars who uses a sentence order that is unusual for us. Instead of building sentences with subject + predicate + object (SPO), Yoda uses the form object + subject + Predicate (OSP), for example in “Begun the Clone War has.” Object and subject are reversed, just like the operands from the example, so that this expression would read like this: “If equals” instead of the usual SPO reading ” if is equal. ”This OSP position is common in Arabic, so that developers from the Arabic-speaking area could actually find this form naturally. If that is not worth a study ...) is the avoidance of errors. If an equals sign is missing in C, it can be compiled as an assignment (although now with a warning), but not. The first incorrect version initializes a variable and always jumps to the statement, since in C every expression (here from the assignment, which is an expression) not equal to 0 is interpreted as true. This is a logical error that the second notation prevents, because it leads to a compiler error. This type of error is not found in Java - unless the variable type is, which is very rare - and so this Yoda notation should be avoided.


2.4.7Logical operators: Not, And, Or, XOR

The processing of program code is often linked to conditions. These conditions are often complex, with three operators appearing most frequently:

  • Not (negation): Reverses the statement; true becomes false, and false becomes true.

  • And (conjunction): Both statements must be true for the overall statement to be true.

  • Or (disjunction): One of the two statements must be true for the overall statement to be true.

Logical operators are used to link truth values ​​according to defined patterns. Logical operators only operate on types; other types lead to compiler errors. Java offers the operators Not (), And (), Or () and XOR (). XOR is an operation that only returns true if exactly one of the two operands is. If both operands are the same (i.e. either or), the result is. XOR also means exclusive or exclusive or. In German, the phrase "either ... or" fits this situation well: Either it's one thing or the other, but not both together. Example: "Do you want to either go to the cinema or watch DVD?"

Table 2.10 Combination of the logical operators Not, And, Or and XOR

The logical operators always work on the type. In Section 22.1.1, "The Bit Operators Complement, And, Or, and XOR," we will see that the same operations can be performed on every bit of an integer.

Prospective logic outlook

Connections of this kind are very important in propositional logic or Boolean algebra. The terms and, or, XOR that are common to us are also known there by other names. The AND connection is called conjunction, the OR connection is called disjunction, and the exclusive or is called contravalence. The three binary operators And, Or, XOR cover certain links, but not all that are possible in principle. In propositional logic there is still the implication (if-then link) and the equivalence. There is no separate operator for either. In the case of the implication, it is the result of, and in the case of logical equivalence, it is the negation of contravalence (XOR), hence also called an exclusive-not-or-connection, i.e. a. Logical equivalence always prevails when both truth values ​​are equal, i.e. either and