Designing Classes and Programs

Announcements
 Homework 3 is due this Wednesday, November 11th
 Superman robot moves into the phone booth.
 Homework 4 will be assigned this week and will be
due next Wednesday, November 18th
 First Midterm
 On November 21st Saturday at 9:00am (~ 100 minutes)
From Selection to Repetition
 The if statement and if/else statement allow a block of statements to be
executed selectively: based on a condition
cout << "Please enter a non-negative number" << endl;
cin >> inputnumber;
if (inputnumber < 0)
{
cout << inputnumber << " is negative. Wrong Input" << endl;
}
 This piece of code does not ask another input number if the number is
negative.
------------------------------------------------------------------------------------------------------
 The while statement repeatedly executes a block of statements while the
condition is true
cout << " Please enter a non-negative number" << endl;
cin >> inputnumber;
while (inputnumber < 0)
{
cout << inputnumber << " is negative! Try again" << endl;
cin >> inputnumber;
}
Semantics of while loop
if (test)
{
statement list;
}
test
false
true
Statement list
Next statement
while (test)
{
statement list;
}
test
false
true
Statement list
Next statement
Sum Example: why we need loops?
 We want to find the sum of 10 positive values
 We can write:
int
int
cin
sum
cin
sum
num1, num2, num3, num4, num5;
sum;
>> num1 >> num2 >> num3 >> num4 >> num5;
= num1 + num2 + num3 + num4 + num5;
>> num1 >> num2 >> num3 >> num4 >> num5;
+= num1 + num2 + num3 + num4 + num5;
Sum Example (not in book)
 What if we want to compute the sum of
 100 values
 an undetermined number of values
 What we need is a program to be able to read as
many values as we want and then compute the
sum
 This is possible with loops
 Good solution is to use loops.
 Code is developed on board. See sum10nums.cpp
 This type of loops are called counting loops
 number of iterations is known
Another simple example
 Calculate the sum of the integer numbers between 1 and 10
int sum = 0;
int i = 1;
while (i <= 10)
{
sum = sum + i;
i += 1;
}
//
//
//
//
this program piece
calculates the sum of
integers between and
including 1 and 10
Walkthrough of the example
i
int sum = 0;
int i = 1;
while (i <= 10)
{
sum = sum + i;
i = i + 1;
}
cout << sum;
sum
i<=10
true
false
sum=sum+i;
i=i+1;
cout<<sum;
1
2
0
1
Walkthrough of the example
i
int sum = 0;
int i = 1;
while (i <= 10)
{
sum = sum + i;
i = i + 1;
}
cout << sum;
sum
i<=10
true
false
sum=sum+i;
i=i+1;
cout<<sum;
2
3
1
3
Walkthrough of the example
i
int sum = 0;
int i = 1;
while (i <= 10)
{
sum = sum + i;
i = i + 1;
}
cout << sum;
sum
i<=10
true
false
sum=sum+i;
i=i+1;
cout<<sum;
3
4
3
6
Walkthrough of the example
i
int sum = 0;
int i = 1;
while (i <= 10)
{
sum = sum + i;
i = i + 1;
}
cout << sum;
sum
i<=10
true
false
sum=sum+i;
i=i+1;
cout<<sum;
10
11
45
55
while loop syntax
<initialization>
while (<test>)
{
<statement1>;
...
<statementN>;
<update>
}
while loop sum example
 Sum of numbers from 1..10
int sum = 0;
int i = 1;
while (i <= 10)
{
sum = sum + i;
i = i + 1;
}
cout << sum;
initialization
test
body statements
update
Anatomy of a loop
 Initialize variables used in loop body and loop test (before the
loop)
 No general rule. The way of initialization and the initial values are to
be determined according to the application
 The loop test is evaluated before each loop iteration
 NOT evaluated after each statement in the loop body
 Current value of variables are used for the loop test before each
iteration
 The loop body must update some variables used in the loop test
so that the loop eventually terminates
 If loop test is always true, loop is infinite
 Infinite loops must be avoided
 Basic rule of designing a loop:
 Initialization, loop test and update parts should be designed carefully
in order to iterate the loop as many times as needed, but not one less
or one more.
 Unfortunately there is no straightforward rule of designing a bug-free
loop
 you should be able to develop those parts by understanding and analyzing
the underlying problem that needs a loop
for loop syntax
for (<initialization>; <test>; <update>)
{
<statement1>;
...
<statementN>;
}
 Initialization, test and update parts are combined
 Good for counting on an index kind of loops.
for loop syntax compared with while
<initialization>
while (<test>)
{
<statement1>;
...
<statementN>;
<update>
}
for (<initialization>;
<test>;
<update> )
{
<statement1>;
...
<statementN>;
}
for loop example
• Rewrite the same loop: sum of numbers from 1..10
int sum = 0;
int i = 1;
while (i <= 10)
{
sum = sum + i;
i = i + 1;
}
int sum = 0;
for (int i=1; i <= 10; i=i+1)
{
sum = sum + i;
}
The for loop
 initialization statement
 executed once before the loop
 test expression
 boolean expression
 checked each time before entering the loop body
 if true execute loop body, if false terminate loop
 update statement
 executed after the last statement of the loop body
 several statements in initialization and update are
separated by comma
for(len = s.length(), k=0; k < len; k+=1)
 initialization and/or test and/or update parts could be
missing
 but semicolons are there
The for loop
 For loops are good for counting loops (although they can be used for
conditional loops)
 Number of iterations known before loop begins
 Example: sum of 10 input numbers
 Example: print a string vertically
void Vertical(string s)
// post: chars of s printed vertically
int len;
int k;
len = s.length();
k = 0;
while (k < len)
{
cout << s.substr(k,1) << endl;
k += 1;
}
// for loop alternative 3
int len;
int k;
len = s.length();
k = 0;
for(; k < len; k+= 1)
{ cout << s.substr(k,1) << endl;
}
// for loop alternative 1
// for loop alternative 2
int len;
int k;
len = s.length();
int len;
int k;
for(k=0; k < len; k+= 1)
for(len = s.length(), k=0; k < len; k+= 1)
{ cout << s.substr(k,1) << endl; { cout << s.substr(k,1) << endl;
}
}
Example: Print a string backwards
(revstring.cpp)
 Determine the index of the last character of the string,
and then access each character backwards
 How many times should the loop iterate ?
string s; int k;
cout << "enter string: ";
cin >> s;
cout << s << " reversed is ";
k = s.length() - 1; // index of last character in s
while (k >= 0)
{
cout << s.substr(k,1);
k -= 1;
}
cout << endl;
 What could we use instead of s.substr(k,1) ?
s.at(k)
Reverse String as a function
 First step, what is the prototype?
string revstring(string s)
// pre: s = c0c1c2…cn-1
// post: return cn-1…c2c1c0
 Second step, how do we build a new string?
 Start with an empty string, ""
 Add one character at each iteration using concatenation, +
rev = rev + s.substr(k,1);
 Use revstring to determine if a string is a palindrome
See palindrome.cpp for full program
string revstring(string s)
// post: returns reverse of s, that is "stab" for "bats“
{
int k = s.length() – 1;
string rev = "";
// start with empty string
while (k >= 0)
{
rev = rev + s.substr(k,1);
k -= 1;
}
return rev;
}
bool IsPalindrome(string word)
// post: returns true if and only word is a palindrome
{
return (word == revstring(word));
}
Bad loops
1. for (int i = 10; i < 5; i++)
{
cout << "How many times do I print?";
}
2.for (int i = 10; i >= 1; i++)
{
cout << "How many times do I print?";
}
3. int i = 1;
while (i < 20)
{
cout << "How many times do I print?";
}
Bad loops
 Never executes
 Never stops (infinite loops)
 Example: consider the following modified code from sum10nums
 What’s the problem in the loop below? What is missing?
sum = 0;
count = 1;
while (count <= 10)
{
cin >> num;
sum += num;
}
 count never reaches 10, because count is not updated in the loop
Infinite loops
 Infinite loop is something that must be avoided
 happens when the loop condition is always true
 same loop body iterates forever
 sometimes you see an output, sometimes you don’t
 press Ctrl-C to stop
 could be because of a wrong or missing update statement
 could be because of a wrong condition; could be another
reason
Infinite loops
 What is the problem with the code below?
 cannot say infinite loop, depends on input number
 for example, if num is an odd number, then the loop is infinite
cin >> num;
int start = 0;
while (start != num)
{
start += 2;
cout << start << endl;
}
 How to fix?
 You can check whether num is even before starting the loop.
if (num % 2 == 0)
{
while (start != num)
{ start += 2;
cout << start << endl;
}
}
Other Common Problems
 Easy to iterate one more or one less times
 Test each loop with the inputs that cause:
 zero iterations of the loop body
 one iteration of the loop body
 maximum number of iterations
 one less than the maximum number of iterations
 Use the debugger and watch the variables.
Developing Loops
 Some loops are easy to develop, others are not
 Sometimes the proper loop test and body are hard to
design
 Practice helps, but remember:
 Good design comes from experience, experience comes
from bad design
Number Crunching
 Number crunching is a CS term that means a computing
operation that requires several (and sometimes
complex) arithmetic operations
 It was the job of early computers
 Numeric Analysis
 classical sub-discipline of computer science
 Today
 implicitly or explicitly, all operations are numeric
 Now we will see some mathematical applications
 factorial calculation
 prime number testing
Factorial
 n! = 1x2x…xn is “n factorial”; used in math, statistics
long factorial(long n)
// pre: 0 <= n
// post: returns n! (1 x 2 x … x n)
 Similar to sum, but this time we will calculate a product
within the loop. At the end we will return the final
product.
 The loop will iterate n times, multiplying by 1, 2, …, n
 Suppose we use a variable called product to hold the result,
then product is n! when the loop terminates. Then we will
return it at the end.
Factorial
long Factorial(int num)
// precondition: num >= 0
// postcondition returns num! (1 x 2 x … x num)
{
long product = 1;
int count = 0;
while (count < num)
{
count += 1;
product *= count;
}
return product;
}
 Issues
 Why did we use long? What happens if we use int instead?
 What happens if we initialize count to 1?
 Let’s see fact.cpp
Factorial (Cont’d) – Using BigInt class
 What is the problem of the previous program?
 integer overflow
 even long is not sufficient (actually there is no difference between
long and int for 32-bit computers like ours)
 12! is 479,001,600 so what happens with 13! ?
 The type BigInt, accessible via #include "bigint.h" can
be used like an int, but gets as big as you want it to be
 Really arbitrarily large?
 No, limited to computer memory, but computers most likely run out of time
before running out of memory
 Disadvantages of using BigInt compared to int?
 processing speed is lower
 uses up more memory
 Use BigInt if you really need it
 Do not forget to add bigint.cpp to your project,
 BigInt is a Tapestry class
 Download wincode.zip file from http://cs.duke.edu/csed/tapestry
Factorial using BigInt class
 See bigfact.cpp
Determining if a number is prime
 Prime number is a natural number which has only two divisors:
1 and itself
 Some Cryptographic algorithms depend on prime numbers
 Determining if a number is prime must be “easy”
 Actually factoring a number must be “hard”
 “hard” in the sense that it must be computationally infeasible to factorize
in a reasonable amount of time
 RSA Cryptosystem
 Rivest, Shamir, Adleman
 based on the factorization problem of large numbers
 has been utilized by several security products and services
 PGP (Pretty Good Privacy) – e-mail security
 WWW security using SSL protocol
 Sophisticated mathematics used for fast prime-testing, we’ll do
basic prime testing
 Since our algorithm is based on factorization, it will be really slow
for large numbers
Determining Primeness (continued)
 1 is NOT prime, 2 is prime, 3 is prime, 5 is prime, 17 is prime, … 137,
193?
 We do not need to check even numbers other than 2 (2 is a special case)
 To check 193, divide it by 3, 5, 7, 9, 11, 13
 Note that 14x14 = 196, so 13 largest potential factor?
 We will use modulus operator to check divisibility
 We’ll check odd numbers as potential divisors
 Watch out for 2, it is a special case
 How far should we go to check potential divisors?
 up to and including sqrt(number) + 1
 If there was a bigger factor, a smaller factor would exist. And this smaller one
must have been checked before. So we do not need to go beyond this limit.
 +1 is there to make sure that there will be no problems with precision
 See primes.cpp for code
Primeness Check – Details
 Special even number check is added before the loop to
eliminate even numbers to be checked in the loop
 In order to make the code more efficient
int limit = int(sqrt(n) + 1);
 To assign a double value to an int, a typecast is used, to tell the
compiler that the loss of precision is intentional
 Make typecasts explicit to tell the compiler you know what you are doing
 Compiler warnings are avoided
 We will see typecast in more detail later
for loop compared with while
<initialization>
while (<test>)
{
<statement1>;
...
<statementN>;
<update>
}
for (<initialization>;
<test>;
<update> )
{
<statement1>;
...
<statementN>;
}
Example
 Rewrite the while loop of main of primes.cpp using for
k = low;
while (k <= high)
{
if (IsPrime(k))
{
cout << k << endl;
numPrimes += 1;
}
k += 1;
}
for (k = low; k <= high; k += 1)
{
if (IsPrime(k))
{
cout << k << endl;
numPrimes += 1;
}
}
Shorthand for increment/decrement
 Lots of code requires incrementing a variable by one
 Three methods, using = and +, using +=, and using ++
 effectively they are same
num = num + 1;
num += 1;
num++;
// post increment
 It is also possible to write ++num;
 pre-increment
 These differ on when the increment is performed, but this
difference doesn’t matter when used as an abbreviation for the
statement n += 1; in a single statement
 Similarly there are post-decrement (and pre-decrement)
num = num - 1;
num -= 1;
num--;
The do-while loop
 Similar to while loop, but the test is after the execution of the loop body
 The while loop may never execute, do-while loop executes at least
once
<initialization>
do
{
<statement1>;
...
<statementN>;
Don’t
forget
<update>
} while (<condition>);
 Example: Prompt for a number between 0 and 100, loop until such a
number is entered (user should enter at least one number)
do
{
cout << "enter number in range [0..100] ";
cin >> num;
} while (num < 0 || num > 100 );
Priming
 Priming: reading an initial value before the loop
 do not get confused with prime numbers; this is something else
 Problem: enter numbers, add them up, stop when -1 entered
int sum = 0;
int num;
cin >> num;
// prime the loop
while (num != -1)
{
sum += num;
cin >> num;
}
cout << "total = " << sum << end;
 Code duplication exists here: input (and perhaps prompt) code is
repeated before the loop and in the loop
Pseudo infinite solution using break
 To avoid repeating code, include it in the body of the loop only,
use a test to break out of the loop
 break statement exits (inner-most) loop
 I don’t prefer this kind of loops (I’d prefer code duplication)
 Because the loop condition is not clear, hence prevents readability
 Try not to use break in this course
 Save it for later when you develop really complicated loops
int sum = 0;
int num;
while (true)
// seemingly infinite loop
{
cin >> num;
if (num == -1)
{ break;
// get out of loop
}
sum += num;
}
cout << "total = " << sum << end;
Fence Post Problem
 The problem that occurs when one or more operations of the loop
body are executed one less then the others.
 Example: Display integers between 1 and 10 separated by comma
1,2,3,4,5,6,7,8,9,10
 no comma after 10; no comma before 1.
for (n=1; n <= 10; n++)
{ cout << n << ",";
}
Problem: comma after 10
for (n=1; n < 10; n++)
{ cout << n << ",";
}
cout << n;
No problem, but code duplicates
 Think of other solutions! (see page 175 of Tapestry)
Downward-counting loop
 Calculate n to the power of m: nm=nxnx…xn
 Example: 25=2x2x2x2x2=32
int
int
cin
for
{
power = 1;
n, m;
>> n >> m;
(int i = m; i <= 1; i--)
power = power * n;
}
Nested loops
 Sometimes one loop occurs in another
 Generating 2-dimensional tabular data
 multiplication table
 Sorting vectors (which will be studied much later)
 Display some geometric figures using character * (or any other
character)
 display rectangles, triangles
 Although other loops can be nested as well, most of the
time, for loops are used in nested manner
Nested loops - Example
 Write a function to display a rectangle of stars (height and width are
parameters)
 e.g. if height is 4 and width is 7, the output should look like
*******
*******
*******
*******
for (i=1; i<= height; i++)
{
for (j=1; j<=width; j++) // inner loop prints 1 line of stars
{
cout << "*";
}
cout << endl;
// end of line is put to the end of each line
}
 See drawfigures.cpp for the complete function and its use in main
Nested loops - Example
 Write a function to display a perpendicular isosceles triangle of stars
(perpendicular side length is parameter)
 e.g. if side length is 6 , the output should look like
*
**
***
****
*****
******
for (i=1; i <= side; i++)
{
for (j=1; j<=i; j++)
// inner loop prints 1 line of stars
{
cout << "*";
}
cout << endl;
// end of line is put to the end of each line
}
 See drawfigures.cpp for the complete function and its use in main
Same loop: downward-counting
for (i=1; i <= side; i++)
{
for (j=1; j<=i; j++)
{
cout << "*";
}
cout << endl;
}
for (i=1; i <= side; i++)
{
for (j=i; j>=1; j--)
{
cout << "*";
}
cout << endl;
}
Drawfigures – Other Considerations
 What about having a function to display a line of stars (number
of stars is a parameter)
 useful for both rectangle and triangle
void PrintLine (int numstars)
// pre: numstars > 0
// post: displays numstars stars in one line
{
int i;
for (i=1; i<= numstars; i++)
{ cout << "*";
}
cout << endl; // end of line is put to the end of the line
}
 in rectangle function, inner loop is replaced by a function call
for (i=1; i<=height ; i++)
{
PrintLine(width);
}
 use of PrintLine in triangle function is similar
Example – Multiplication Table
 On ith line print, i*1, i*2, i*3, ... , i*i
 Total number of lines is an input. Display lines starting with 1.
 See multiply.cpp
#include <iostream>
#include <iomanip>
// for setw
using namespace std;
int main()
{
int i,k,numlines;
const int WIDTH = 4;
cin >> numlines;
}
for (i=1; i <= numlines; i++)
{
for (k=1; k <= i; k++)
{
cout << setw(WIDTH) << i*k;
}
cout << endl;
}
return 0;
Constants
 Sometimes very useful
 provides self documentation
 re-use the same value across the program
 avoid accidental value changes
 like variables, but their value is assigned at declaration
and can never change afterwards
 declared by using const before the type name (any type is OK)
const double PI = 3.14159;
const string thisclass = "CS201"
const int
WIDTH = 4;
 later you can use their value
cout << (PI * 4 * 4);
 but cannot change their value
PI = 3.14;
causes a syntax error
Formatting Output
 We use stream manipulator setw to specify the total number of
spaces that the next output will use
 setw(field length)
 written in cout and affects only the next output value
not the whole cout line
 output is displayed using field length spaces in right justified manner
(any empty space is on the left)
 defined in header file <iomanip>, so you have to have #include
<iomanip>
 Example
cout << setw(9) << "cs201";
 output shown is four blanks and cs201
Example using robot class (see rectangularscan.cpp)
 Write a program in which the robot starts at 0,0 and
searches a rectangular space that covers n*n cells
 n is input (in the example below, n is 8)
 during this journey the robot should pick or put things on the
cells so that all visited cells occupy one thing