The course dictionary (which is the source of all the rollover definitions in the website) defines an expression as follows:

A combination of variables, constants, operators and functions which is progressively evaluated an operation at a time until it is reduced to a final value.

You're familiar with expressions from mathematics and we have built on that familiarity already by using expressions in a limited fashion. Its time to introduce them more formally.

The crucial thing about expressions is the last part of that definition. When an expression is run as part of a program, it is always reduced to a single value. That expression reduction process is called evaluation.

Here is a list of statements that include expressions, most lifted from the previous topics (possibly in modified form):

statement expression included
e;
e
pi = 3.14159;
pi = 3.14159
return (base * height)/ 2; (base * height)/ 2
speed(distance, time); speed(distance, time)

Even just the occurrence of a variable or constant by itself is an expression because it can be evaluated. If e represents the charge on an electron it is 1.60217646e-19. Similarly, a function call by itself is an expression, because it can be evaluated.

Arithmetic Expressions

Arithmetic expressions are based on the use of arithmetic operators. The first thing you have to understand is that computers have two sets of special hardware for doing arithmetic—one set for integer arithmetic and one set for real (in the form of doubles) arithmetic. Whenever you create an arithmetic operation, the machine has to decide which set of hardware to use. The integer hardware is much faster. The double hardware can handle real numbers.

Every operation involves an operator and either one or two operands (the values being operated on by the operator). The decision as to which piece of hardware to invoke is based on the type of the operands.

Double Arithmetic

We characterize C++ operators as being

  1. Unary (one operand): + -
  2. Binary (two operands) + - * /

where * and / signify respectively multiplication and division. C++ has no exponentiation operator.

Here's an example of the unary + and - at work.

double a = -4.3;
double b = -5.73;
double x = 2.0;
y = 2*x *(-b) + 3.4*x*(+a);

The minus signs in -4.3 and -5,73 are part of the literal values. However, the unary minus applied to b is clearly an operator . It means take whatever b's value is (positive or negative) and negate it (reverse the sign). The value of the unary + as applied to a might be dubious but it is legal. Unary + is part of the language for the sake of consistency.

The four multiplies (*) and one addition in the example above are examples of binary operations. They each have two operands, one to the left of the operator and one to the right. Evaluation of the expression is carried out one operation at a time.

In double arithmetic, all operands are double and the result is always double. Consider the following function to compute the quadratic x2+2x+1.5 for any x (without an exponentiation operator, x*x is used in place of x2). Focus on the step by step evaluation of the quadratic expression within the Expression Engine.

Integer Arithmetic

The int operators are

  1. Unary (one operand): + -
  2. Binary (two operands) + - * / %

where * and / signify respectively multiplication and division. Notice that integer arithmetic has an extra operator. The % operator, known as the modulo operator, computes the remainder of an integer division. In integer arithmetic, all operands are int and the result is always int

The results are what you would expect until you get to division.

In normal arithmetic 11/7 would be 1.571. However, the result of an integer operation is always an integer.

So why not 2?

C++ int arithmetic doesn't round. Instead it gives us two int division operators.

  1. / gives us the integer part.
  2. % gives us the remainder

This is exactly arithmetic as you first learned it in grade school, before you learned "decimals". Seven goes into eleven one time with four left over.

Conversions

ints and doubles are different types. Computers can

They can't do mixed arithmetic. Instead, they convert from one type to the other.

In the example evaluation of the term 2 * x requires an implicit conversion.

The 2 is automatically converted to a double yielding 2.0 * x and then a double multiply is called.

Explicit Casting

A programmer can also force a conversion explicitly by doing a type cast.

int y = 2 * (int) x;

Here the operator (int) is an int type cast applied to the double variable x coercing it to an int.

This is known as a downcast because precision is lost. Downcasting also occurs in the following example because, although the expressionis evaluated using doubles, the final result is returned as an int. There's no video for this one. At this point in the course you should be able to run it yourself.

Rounding

When a double is converted to an int, it is not rounded, it is truncated.

The fractional part is discarded

This is consistent with the integer / operator's behaviour.

Here's how you round positive nos.

The technique has to be ammended for negative nos. We'll show you how later.

Compiler Warnings

Many compilers, including Eclipse, will warn you about downcasts. Such warnings are not syntax errors. Rather, they are telling the programmer that a logical error is likely to occur. Crudely, a logical error is one that occurs once you start the program running.

Composite Assignment Operators

There are some special shorthand assignment operators in C++, created because the original designer of C didn't like to type more than necessary. We just show them by example.

x += 2;       means     x = x+2;

x -= 2;       means     x = x-2;

x *= 2;       means     x = x*2;

x /= 2;       means     x = x/2;

Again, remember, these aren't equations. They're assignments. We evaluate the right side that write the value into the left side. The Teaching Machine will automatically convert compound assignment expression to the right hand form in the Expression Engine.

Order of Evaluation

The order of evaluation in compound expressions is determined by

  1. Parenthesis ( )
  2. Precedence
    unary  - , + Highest (evaluated first)
    *, /, %  
    -, + Lowest (evaluated last)

For example, given the expression 4+3*2, the multiply operation is carried out before the addition because multiply has a higher precedence than addition. Thus the value of the expression is 10 instead of 14. Here are a few simple examples.

Library Functions

There are thousands of prebuilt functions available in dozens of libraries

The header files mostly contain the declarations needed to use the libraries

For example, the math library has declarations for

To use any of these functions you would add to the top of your file the line

#include <cmath>

This is a very special line of code. The # which starts it means it is actually a command to the precompiler.

The precompiler is a kind of administrative assistant to the compiler. What this line really means is "I want to use the cmath library so go and get it and add it to our program." The compiler never sees this line of code. Instead it sees special lines of code inserted by the precompiler that it needs in order to be able to use the cmath library.

Here is a package of functons to provide services for conversion between rectangular and polar co-ordinates.

Note that the functions we build are calling library functions. Up to now, we have built or implemented functions, thus providing a service for someone else.

When call a function, it means that we are the client making use of a service provided by some other developer.

Some special lines of note:

In polarMag we have the following:

return sqrt(pow(x,2) + pow(y,2))

sqrt is the square root function as provided by the cmath library and as you would expect, it takes a single double argument.

For that argument, we are actully giving it an expression that has two other function calls in it.

Thus we can have function calls embedded in function calls—now we're getting some power!

Also note

As the comment says, neither C nor C++ have a built-in value for π so we calculate it on the fly. This is much better than typing something like 3.14159 because our calculation gives us the full precision of the floating point processor built in to the computer.

Still, creating a function to do it is inefficient, since we have to recompute pi every time we need it. What we need is a constant available throughout our entire program.

The solution, as it appeared in one of your assignments, is to create a computed constant

const double PI = 4.0 * atan(1.0);

and then put it into an h file which can be shared throughout the program.

Exercises

Your textbooks are full of formulae. Pick some out and write functions for them. For example, from circuits:

  1. Equivalent resistance of a pair of resistors in parallel is given by their product divided by their sum.
  2. The voltage output from a voltage divider is the input voltage times the lower resistor divided by the sum of the lower and upper resistors.
  3. Given an element with a phasor voltage across it (Vpk, Θ)and a phasor current through it(Ipk, Φ), the real power dissipated by the element is the square root of (Vpk×Ipk) times the cosine of the difference between the two angles.

Examples Shown in Full