Most of you are familiar with expressions involving addition, subtraction, multiplication and division from Java or Python. However, when it comes to C++ you’ll find a few surprises. We want to start this lesson by discussing the differences between integer division and normal or true division.
Integer division works like grade-school long division. You draw a little "house" on the board and put the "maximum occupancy" (called the dividend) inside the house. That is the number you want to divide.
Next, you draw the number you want to divide by (the divisor), standing at the front door of the house like a group of visitors. In the picture, you can see we have a dividend of 253 and a divisor of 5.
Then you ask, "how many groups" (of 5 in this case), could fit inside the house and place that number on the roof. This is the quotient.
You multiply the quotient by the divisor, place the result beneath the dividend, and subtract. The remainder is anything left over (down in the "basement"), 8 in the example the student is solving on the board (on the left), and 3 in the example on the callout.
In C++ integer division, the quotient is calculated, and then truncated (not rounded). The remainder is discarded. With true division, 15/4 would be 3.75 but with integer division, it's just 3, not 4 as it would be if the 3.75 were rounded.
The Remainder Operator
The % or remainder operator (sometimes called the modulus operator) does exactly the same thing, except, instead of returning the quotient portion from the roof, it returns the remainder from the basement.
Here are some examples:
cout << 1 / 3 << endl; // 0 int division
cout << 1.0 / 3 << endl; // .3333 true division
cout << 12 % 5 << endl; // 2 left over after 12 / 5
Assignment Operators
With the expression cout << 11, the cout object is changed and the character pair 11 appears on the screen. Both the change to cout and the printing on the screen are called side effects. Here are some other side-effect operators.
Chained Assignment
When using the assignment operator, the result or value of the expression is the value that is copied. Because assignment is right associative, we can "chain" assignment statements together like this:
int x, y, z;
x = y = z = 10; // chained assignment, which means...
x = y = (z = 10); // right associative, which means...
x = (y = 10);
x = 10;
Shorthand Assignment
To modify an existing variable, use the shorthand-assignment operators:
x += 5; // means x = x + 5
x -= 5; // means x = x - 5
x *= 5; // means x = x * 5
x /= 5; // means x = x / 5
x %= 5; // means x = x % 5
Increment and Decrement
To add or subtract one from a variable use increment (++) and decrement (--) operators. These are unary operators that can only be applied to a variable (lvalue).
int a = 5, b = 10;
a++; // a is changed to 6
--b; // b is changed to 9
In addition to the side effect (changing the variable), expressions using these operators produce a value. When placed before a variable, it is called pre-increment (or decrement); when placed after, it is called a post-increment (or decrement) expression. The side effect is the same for both: the variable is left with a value one greater (or less) than it was before.
The expression value (result) produced depends on whether the expression uses post or pre-increment.
int a = 5, b = 10, c, d;
c = a++; // a is changed to 6; c is assigned 5
d = --b; // b is changed to 9 and so is d
With pre-increment, the variable is first modified and the modified variable is returned as the value. A prefix expression is thus an lvalue, so the expression ++++a is legal.
With post-increment, the original value is saved to a temporary location. Then, the variable is changed. Finally, the temporary value is returned from the expression. That's why c in the example above is given the value 5 and not 6. A postfix expression is an rvalue, so the expression a++++ is illegal.
A Side-effect Pitfall
Don't ever use any side-effect operator twice on the same variable in the same expression. These expressions all result in undefined behavior, as you'll see if you run the code yourself in g++ , visual c++ or in clang++ .
int n = 6;
print(n, ++n); // passing 6,7 or 7,7? Can't tell!
int a = n * n++;
n = n++;
cout << n++ << n++ << n++ << endl;
Mixed-type Expressions
Every expression produces a value, and each value produced has a particular type. Thus, when you add or subtract two integers, the result is an integer. But what if....
a = 5 * 3.5;
The CPU uses different circuitry for integer and floating-point calculations. To evaluate this expression, both operands must be type int, or, they both must be type double. If we convert both to int, we lose information; converting them to double does not.
When your compiler encounters an expression that uses different types, it determines the operand with the greatest information potential. It then creates temporary values of that type, initializing them with the other values. This is called promotion.
Assignment and Mixed Expressions
What is stored in a in the example shown above? That depends on the type of a. If the variable is other than double, the value is again, implicitly converted into the same type as the variable. Thus, while the value calculated is 17.5, if a has type int then only the 17 will be stored.
- Widening conversions occur when the assignment causes a promotion, such as from int to double. These will always succeed (just as they do in Java or C#).
- Narrowing conversions occur when the assignment has the potential for losing information, such as assigning from double to int.
Narrowing implicit assignment conversions are prohibited in Java and C#, but they are the default behavior in C++. To turn off such implicit narrowing conversions, C++11 added brace or list assignment; this makes C++ work more like Java and C#.
int a, b;
a = 5 * 3.5; // 17; implicit narrowing conversion
b = 17.5; // c++11+; compiler error
Type Casts
You can specify an explicit conversion by using a type cast, like this:
int numerator = 5, denominator = 7;
double bad = numerator / denominator; // OOPS!!! now 0
double good = static_cast<double>(numerator) / denominator;
- numerator and denominator are both integers
- bad is a double, but the calculation uses int, so bad ends up with 0.0.
- static_cast creates a temporary, anonymous double to "stand in" for numerator during the calculation, so floating-point (true) division is performed instead of integer division.
There are four named casts. We'll meet others later. Bjarne Stroustrup, (the inventor of C++) has listed several reasons why you should use these new-style casts on his C++ FAQ.
Functions
A mathematical function such as f(x) = x2 + 1, means that ƒ(x) computes a value equivalent to the square of x plus one. For any value x, you can compute the value of the function by applying the formula; thus ƒ(3) is 32 + 1, or 10.
In C++ a function is a block of code that has been given a name. To run that code, you call the function. To call a function in C++, you write the name of the function, followed by a list of arguments in parentheses. Here is a call to the function named f, passing the argument 3:
cout << f(3) << endl;
We can implement the function f(x) in C++ like this:
double f(double x)
{
return x * x + 1;
}
When called, the function copies the data supplied as arguments into the appropriate parameter variables (x in this example), and then executes the code in its body. When finished, control returns to the point in the code from which the call was made.
The operation of going back to the calling program is called returning from the function. A function often passes a value back to its caller. This is called returning a value
The <cmath> Header
C++ has an extensive standard mathematical library called <cmath> that includes many of the pre-built functions you are likely to use. After including the <cmath> header, you can use the functions just like this:
double root = sqrt(value);
In this case, sqrt is the function, value is the argument passed (or copied) into the function, and root is where the answer, returned from the function, will be stored.
Notice, that unlike Java, we don't use method call syntax, like Math.sqrt() to call the math functions in the standard library.
Normally, you'll just look up the math functions online online when you need them. However, you should be able to use sqrt(), abs() and pow() without refering to the documentation.