• No results found

Algorithms

In document C++ (Page 77-89)

Do not accidentally reverse the order of the symbols for the arithmetic assignment operators, like in the statement

x =+ 5;

Notice that the + and = symbols have been reversed. The compiler interprets this statement as if it had been written

x = +5;

that is, assignment and the unary operator. This assigns x to exactly five instead of increasing it by five.

Similarly,

x =- 3;

would assign −3 to x instead of decreasing x by three.

Appendix D examines some additional arithmetic operators available in C++.

4.9

Algorithms

An algorithm is a finite sequence of steps, each step taking a finite length of time, that solves a problem or computes a result. A computer program is one example of an algorithm, as is a recipe to make lasagna. In both of these examples, the order of the steps matter. In the case of lasagna, the noodles must be cooked in boiling water before they are layered into the filling to be baked. It would be inappropriate to place the raw noodles into the pan with all the other ingredients, bake it, and then later remove the already baked noodles to cook them in boiling water separately. In the same way, the ordering of steps is very important in a computer program. While this point may be obvious, consider the following sound argument:

1. The relationship between degrees Celsius and degrees Fahrenheit can be expressed as ◦

C=5 9× (

◦ F− 32)

2. Given a temperature in degrees Fahrenheit, the corresponding temperature in degrees Celsius can be computed.

Armed with this knowledge, Listing 4.14 (faultytempconv.cpp) follows directly.

Listing 4.14: faultytempconv.cpp 1 // File faultytempconv.cpp 2 3 #include <iostream> 4 5 using namespace std; 6 7 int main() 8 {

4.9. ALGORITHMS 67

10 // Define the relationship between F and C

11 degreesC = 5.0/9*(degreesF - 32); 12 // Prompt user for degrees F

13 cout << "Enter the temperature in degrees F: "; 14 // Read in the user's input

15 cin >> degreesF; 16 // Report the result

17 cout << degreesC << endl;

18 }

Unfortunately, the executing program always displays

-17.7778

regardless of the input provided. The English description provided above is correct. No integer division problems lurk, as in Listing 4.10 (tempconv.cpp). The problem lies simply in statement ordering. The statement

degreesC = 5.0/9*(degreesF - 32);

is an assignment statement, not a definition of a relationship that exists throughout the program. At the point of the assignment, degreesF has the value of zero. The variable degreesC is assigned before

degreesF’s value is received from the user.

As another example, suppose x and y are two variables in some program. How would we interchange the values of the two variables? We want x to have y’s original value and y to have x’s original value. This code may seem reasonable:

x = y; y = x;

The problem with this section of code is that after the first statement is executed, x and y both have the same value (y’s original value). The second assignment is superfluous and does nothing to change the values of

xor y. The solution requires a third variable to remember the original value of one the variables before it is reassigned. The correct code to swap the values is

temp = x; x = y; y = temp;

This small example emphasizes the fact that algorithms must be specified precisely. Informal notions about how to solve a problem can be valuable in the early stages of program design, but the coded program requires a correct detailed description of the solution.

The algorithms we have seen so far have been simple. Statement 1, followed by Statement 2, etc. until every statement in the program has been executed. Chapter 5 and Chapter 6 introduce some language constructs that permit optional and repetitive execution of some statements. These constructs allow us to build programs that do much more interesting things, but more complex algorithms are required to make it happen. We must not lose sight of the fact that a complicated algorithm that is 99% correct is not correct. An algorithm’s design and implementation can be derailed by inattention to the smallest of details.

4.10. SUMMARY 68

4.10

Summary

• The literal value 4 and integer sum are examples of simple C++numeric expressions. • 2*x + 4 is an example of a more complex C++numeric expression.

• Expressions can be printed via the cout output stream object and assigned to variables. • A binary operator performs an operation using two operands.

• With regard to binary operators: + represents arithmetic addition; - represents arithmetic subtrac- tion; * represents arithmetic multiplication; / represents arithmetic division; % represents arithmetic modulus, or integer remainder after division.

• The std::cin object can be used to assign user keyboard input to variables when the program is executing.

• The >> operator is called the extraction operator. It assigns to variables data extracted from the input stream object cin.

• A unary operator performs an operation using one operand. • The - unary operator represents the additive inverse of its operand. • The + unary operator has no effect on its operand.

• Arithmetic applied to integer operands yields integer results.

• With a binary operation, double-precision floating-point arithmetic is performed if at least one of its operands is a floating-point number.

• Floating-point arithmetic is inexact and subject to rounding errors because all floating-point values have finite precision.

• When a floating-point value is assigned to an integer variable, the value is truncated, not properly rounded.

• A mixed expression is an expression that contains values and/or variables of differing types.

• Generally speaking, a type is narrower than another type if its range of values is smaller than the other type; a type is wider than another type if its range of values is larger than the other type. • A wider type dominates a narrower type.

• In mixed arithmetic with a binary operator, the type of arithmetic performed is determined by the more dominant operand.

• Floating point values can be assigned to integer variables, but any fractional part will be truncated. Programmers must ensure that the value assigned falls within the range of integers.

• In C++a wider type may be assigned to a narrower type, but a floating-point to integer conversion truncates, and a value outside the range of the narrower type results in a bogus value being assigned. Programmers should use caution when assigning a wider type to a narrower type.

4.10. SUMMARY 69

• With regard to the arithmetic operators, C++uses the same precedence rules as standard arithmetic: multiplication and division are applied before addition and subtraction unless parentheses dictate otherwise.

• The arithmetic operators associate left to right; assignment associates right to left.

• Chained assignment can be used to assign the same value to multiple variables within one statement. • The unary operators + and - have precedence over the binary arithmetic operators *, /, and %, which have precedence over the binary arithmetic operators + and -, which have precedence over the assignment operator.

• Comments are notes within the source code. The compiler ignores comments when compiling the source code.

• Comments inform human readers about the code.

• Comments should not state the obvious, but it is better to provide too many comments rather than too few.

• A single line comment begins with the symbols//and continues until the end of the line.

• A block comment begins with the symbols/*and continues in the source code until the symbols */ terminate it.

• Source code should be formatted so that it is more easily read and understood by humans. • C++has some general formatting guidelines that should be followed:

– Each statement should appear on its own line.

– Curly braces should be aligned in order to be matched visually more quickly.

– The statements that comprise the body of a function should be indented; four spaces are gener- ally accepted as ideal.

– Spaces should be used within statements separating the logical pieces to make the statements easier to read.

• Compile-time errors are caused by the programmer’s misuse of the C++ language. Compile-time errors are detected and reported by the compiler (and sometimes the linker).

• Runtime errors are errors that are detected when the program is executing. When a run-time error arises, the program terminates with an error message.

• Logic errors elude detection by the compiler and run-time environment. A logic error is indicated when the the program does not behave as expected.

• The compiler should be set at the highest warning level to check for as many problems as possible. Warnings should be taken seriously, and a program should not be considered finished while warnings remain.

• In complicated arithmetic expressions involving many operators and operands, the rules pertaining to mixed arithmetic are applied on an operator-by-operator basis, following the precedence and asso- ciativity laws, not globally over the entire expression.

4.11. EXERCISES 70

• The family of op= operators (+=, -=, *=, /=, and %=) allow variables to be changed by a given amount using a particular arithmetic operator.

• C++programs implement algorithms; as such, C++statements do not declare statements of fact or define relationships that hold throughout the program’s execution; rather they indicate how the values of variables change as the execution of the program progresses.

4.11

Exercises

1. Is the literal 4 a valid C++expression? 2. Is the variable x a valid C++expression? 3. Is x + 4 a valid C++expression?

4. What affect does the unary + operator have when applied to a numeric expression? 5. Sort the following binary operators in order of high to low precedence: +, -, *, /, %, =. 6. Given the following declaration:

int x = 2;

Indicate what each of the following C++statements would print. (a) cout << "x"<< endl;

(b) cout << 'x'<< endl;

(c) cout << x << endl; (d) cout << "x + 1"<< endl;

(e) cout << 'x'+ 1 << endl;

(f) cout << x + 1 << endl;

7. Sort the following types in order from narrowest to widest:int,double,float,long,char. 8. Given the following declarations:

int i1 = 2, i2 = 5, i3 = -3;

double d1 = 2.0, d2 = 5.0, d3 = -0.5;

Evaluate each of the following C++expressions. (a) i1 + i2 (b) i1 / i2 (c) i2 / i1 (d) i1 * i3 (e) d1 + d2 (f) d1 / d2 (g) d2 / d1 (h) d3 * d1 (i) d1 + i2

4.11. EXERCISES 71 (j) i1 / d2 (k) d2 / i1 (l) i2 / d1 (m) i1/i2*d1 (n) d1*i1/i2 (o) d1/d2*i1 (p) i1*d1/d2 (q) i2/i1*d1 (r) d1*i2/i1 (s) d2/d1*i1 (t) i1*d2/d1

9. What is printed by the following statement:

cout << /* 5 */ 3 << endl;

10. Given the following declarations:

int i1 = 2, i2 = 5, i3 = -3;

double d1 = 2.0, d2 = 5.0, d3 = -0.5;

Evaluate each of the following C++expressions. (a) i1 + (i2 * i3)

(b) i1 * (i2 + i3) (c) i1 / (i2 + i3) (d) i1 / i2 + i3 (e) 3 + 4 + 5 / 3 (f) (3 + 4 + 5) / 3 (g) d1 + (d2 * d3) (h) d1 + d2 * d3 (i) d1 / d2 - d3 (j) d1 / (d2 - d3) (k) d1 + d2 + d3 / 3 (l) (d1 + d2 + d3) / 3 (m) d1 + d2 + (d3 / 3) (n) 3 * (d1 + d2) * (d1 - d3)

11. How are single-line comments different from block comments? 12. Can block comments be nested?

13. Which is better, too many comments or too few comments? 14. What is the purpose of comments?

4.11. EXERCISES 72

15. The programs in Listing 3.4 (variable.cpp), Listing 4.5 (reformattedvariable.cpp), and Listing 4.6 (reformattedvariable2.cpp) compile to the same machine code and behave exactly the same. What makes one of the programs clearly better than the others?

16. Why is human readability such an important consideration?

17. Consider the following program which contains some errors. You may assume that the comments within the program accurately describe the program’s intended behavior.

#include <iostream>

using namespace std;

int main() {

int n1, n2, d1; // 1

// Get two numbers from the user

cin << n1 << n2; // 2 // Compute sum of the two numbers

cout << n1 + n2 << endl; // 3 // Compute average of the two numbers cout << n1+n2/2 << endl; // 4 // Assign some variables

d1 = d2 = 0; // 5 // Compute a quotient cout << n1/d1 << endl; // 6 // Compute a product n1*n2 = d1; // 7 // Print result cout << d1 << endl; // 8 }

For each line listed in the comments, indicate whether or not a compile-time, run-time, or logic error is present. Not all lines contain an error.

18. What distinguishes a compiler warning from a compiler error? Should you be concerned about warnings? Why or why not?

19. What are the advantages to enhancing the warning reporting capabilities of the compiler? 20. Write the shortest way to express each of the following statements.

(a) x = x + 1; (b) x = x / 2; (c) x = x - 1; (d) x = x + y; (e) x = x - (y + 7); (f) x = 2*x; (g) number_of_closed_cases = number_of_closed_cases + 2*ncc;

4.11. EXERCISES 73

21. What is printed by the following code fragment? int x1 = 2, y1, x2 = 2, y2; y1 = ++x1;

y2 = x2++;

cout << x1 << " " << x2 << endl; cout << y1 << " " << y2 << endl;

Why does the output appear as it does?

22. Consider the following program that attempts to compute the circumference of a circle given the radius entered by the user. Given a circle’s radius, r, the circle’s circumference, C is given by the formula: C= 2πr #include <iostream> using namespace std; int main() { double C, r; const double PI = 3.14159;

// Formula for the area of a circle given its radius C = 2*PI*r;

// Get the radius from the user

cout >> "Please enter the circle's radius: "; cin << r;

// Print the circumference

cout << "Circumference is " << C << endl; }

(a) The compiler issues a warning. What is the warning? (b) The program does not produce the intended result. Why?

(c) How can it be repaired so that it not only eliminates the warning but also removes the logic error?

23. Write a C++program that ... 24. Write a C++program that ...

75

Chapter 5

Conditional Execution

All the programs in the preceding chapters execute exactly the same statements regardless of the input, if any, provided to them. They follow a linear sequence: Statement 1, Statement 2, etc. until the last statement is executed and the program terminates. Linear programs like these are very limited in the problems they can solve. This chapter introduces constructs that allow program statements to be optionally executed, depending on the context (input) of the program’s execution.

5.1

Type bool

Arithmetic expressions evaluate to numeric values; a Boolean expression, sometimes called a predicate, evaluates totrueorfalse. While Boolean expressions may appear very limited on the surface, they are essential for building more interesting and useful programs.

C++supports the non-numeric data typebool, which stands for Boolean. The term Boolean comes from the name of the British mathematician George Boole. A branch of discrete mathematics called Boolean algebra is dedicated to the study of the properties and the manipulation of logical expressions. Compared to the numeric types, thebooltype is very simple in that it can represent only two values: trueorfalse. Listing 5.1 (boolvars.cpp) is a simple program that shows how Boolean variables can be used. Listing 5.1: boolvars.cpp 1 #include <iostream> 2 3 using namespace std; 4 5 int main() 6 {

7 // Declare some Boolean variables

8 bool a = true, b = false;

9 cout << "a = " << a << ", b = " << b << endl; 10 // Reassign a

11 a = false;

12 cout << "a = " << a << ", b = " << b << endl; 13 // Mix integers and Booleans

5.2. BOOLEAN EXPRESSIONS 76

Operator Meaning

== Equal to

< Less than

> Greater than

<= Less than or equal to

>= Greater than or equal to

!= Not equal to

Table 5.1: C++Relational operators

15 b = 1;

16 cout << "a = " << a << ", b = " << b << endl; 17 // Assign Boolean value to an integer

18 int x = a, y = true; 19 cout << "a = " << a << ", b = " << b 20 << ", x = " << x << ", y = " << y << endl; 21 // More mixing 22 a = 1725; // Warning issued 23 b = -19; // Warning issued

24 cout << "a = " << a << ", b = " << b << endl;

25 }

As you can see from running Listing 5.1 (boolvars.cpp), the Boolean valuesfalseand trueare represented as integer 0 and integer 1. More precisely, zero represents theboolvaluefalse, and any non-zero integer (positive or negative) meanstrue. The direct assignment to aboolvariable of an integer other than 0 or 1 may result in a warning (Visual C++reports truncation of ’int’ to ’bool’), but the variable is still interpreted as true. The data typebool is basically a convenience for programmers; any C++ program that usesboolvariables can be rewritten using integers instead to achieve the same results. While Boolean values and variables are freely compatible and interchangeable with integers, thebooltype is convenient and should be used when the context involves truth values instead of numbers.

It is important to note that the Visual C++compiler issues warnings for the last two assignment state- ments in Listing 5.1 (boolvars.cpp). Even though any non-zero value is consideredtrue, 1 is the preferred integer equivalent totrue(as you can see when you attempt to print the literal valuetrue). Since the need to assign to a Boolean variable a value other thantrueorfalseor the equivalent 1 or 0 should be extremely rare, the compiler’s message alerts the programmer to check to make sure the assignment is not a mistake.

5.2

Boolean Expressions

The simplest Boolean expressions arefalseandtrue, the Boolean literals. A Boolean variable is also a Boolean expression. An expression comparing numeric expressions for equality or inequality is also a Boolean expression. These comparisons are done using relational operators. Table 5.1 lists the relational operators available in C++.

Table 5.2 shows some simple Boolean expressions with their associated values. An expression like

10 < 20is legal but of little use, since the expressiontrue is equivalent, simpler, and less likely to confuse human readers. Boolean expressions are extremely useful when their truth values depend on the values of one or more variables.

5.2. BOOLEAN EXPRESSIONS 77

Expression Value 10 < 20 always true

10 >= 20 always false

x == 10 true only if x has the value 10

X != y true unless x and y have the same values

Table 5.2: Relational operator examples

The relational operators are binary operators and are all left associative. They all have a lower prece- dence than any of the arithmetic operators; therefore, the expression

x + 2 < y / 10

is evaluated as if parentheses were placed as so:

(x + 2) < (y / 10)

C++allows statements to be simple expressions; for example, the statement

x == 15;

may look like an attempt to assign the value 15 to the variable x, but it is not. The = operator performs assignment, but the == operator checks for relational equality. If you make a mistake and use == as shown here, Visual C++will issue a warning that includes the message

warning C4553: ’==’ : operator has no effect; did you intend ’=’? Recall from Section 4.6.4 that a compiler warning does not indicate a violation of the rules of the language; rather it alerts the programmer to a possible trouble spot in the code.

Another example of an expression used as a statement is

x + 15;

This statement is a legal (but useless) C++statement, and the compiler notifies us accordingly:

warning C4552: ’+’ : operator has no effect; expected operator with side-effect

Why are expressions allowed as statements? Some simple expressions have side effects that do alter the behavior of the program. One example of such an ex- pression is x++. Listing 4.13 (prevspost.cpp) showed how x++ can be used as a standalone statement and behave as an expression within a larger statement. A more common example is the use of a function call (which is an expression) as standalone a statement. (We introduce functions in Chapter 8.) In order to keep the structure of the language as uniform as possible, C++ tolerates useless ex- pressions as statements to enable programmers to use the more useful expression- statements. Fortunately, most compilers issue informative warnings about the use- less expression-statements to keep developers on track.

In document C++ (Page 77-89)