Uploaded by Lieutenant

PF-RepetitousStatments 10

advertisement
PROGRAMMING
FUNDAMENTALS
Dr. Sheikh Faisal Rashid
shfaisal@gmail.com,uet.edu.pk
Department of Computer Science and
Engineering UET Lahore
REPETITIOUS
OPERATIONS
Outline
• In this presentation, we will:
• Review conditional statements
• Introduce repetitious operations
• Review the game of PictionaryTM
• Describe how these solve specific real-wold problems
• Understand the need for true/false conditions to continue looping
• Look at the flow chart
Conditional statements
• In real-world situations, you take actions based on criteria
or conditions
• Programming languages restrict decisions to only those that are
absolutely necessary to accomplish goals
• This boils down to Boolean-valued conditional statements
if ( condition ) {
// Do something…
} else {
// Do something else…
}
Repetitious operations
• Another possibility is to repeat an operation until some
goal is accomplished
• In Pictionary, you are given a word and you must get the audience
to guess the word based on a drawing
Repetitious operations
• A more realistic version
followed by many players
• Each decision is not really
objective
• What is “close”?
• What is “sort-of”?
Repetitious operations
• In mathematics, you learned a number of algorithms that
depended on repetition:
• To determine if n is prime:
• Try dividing n by every integer k = 2, …, n – 1
• If any remainder is zero, then n is not prime
• Even long division is a repetitive algorithm:
• In calculating m ÷ n, perform the following:
• Take the first digit of m and call it r
• Find the largest integer multiple d of n such that r – dn ≥ 0, record d and
let
r – dn be the new r
• Add the next digit of m to the new r
Repetitious operations
• In mathematics, you learned a number of algorithms that
depended on repetition:
• To calculate n!
• You multiplied together all of the integers k = 2, …, n
• To calculate
factorial
n
 
k 
, you find
n!
 n  k !k !
which requires three
n  n  1 n  2 
calculations followed by one long division
• You can reduce your work by calculating
and then dividing by k!
 n  k  1
Repetitious operations
• In programming languages, it is also necessary to
repetitively perform a sequence of actions
• In Pictionary, the choice of action was someone fuzzy
• In mathematics, in each case the repetitive operation is well
defined
• In some cases, we know how often we will have to repeat an
operation, in others, we may not know until we get a solution
• That is, if a solution even exists
• Like decision making, in programming languages we will
have to reduce the decision as to how often to repeat
down to a simple yes-no question
Flow charts
• A flow chart for simple repetition is to continue repeating a
code block as long as some condition is TRUE
• As soon as the condition is FALSE, we proceed to other statements
Flow charts
• The repetitive behavior of this repetitive flow chart
component leads to the name looping statement
• We continue looping until a condition fails
Looping statements
• We implemented conditional statements based on a
condition being evaluated to TRUE
if ( condition ) {
// Do something...
} else {
// Do something else...
}
Looping statements
• A looping statement is implemented based on repeatedly
executing a block of statements so long as a condition is
TRUE
while ( Boolean-valued condition ) {
The looped block of statements
- to be executed as long as the
condition is 'true'
}
// Continue executing here as soon as the
// condition evaluates to 'false'
Looping statements
• Because this state block is repeatedly executed (i.e.,
looped) while a condition is TRUE, we refer to such a
statement as a “while loop”
while ( Boolean-valued condition ) {
The looped block of statements
- to be executed as long as the
condition is 'true'
}
// Continue executing here as soon as the
// condition evaluates to 'false'
Looping statements
• The easiest while loop is one that does so forever:
#include <iostream>
int main();
int main() {
// @non-terminating@
while ( true ) {
std::cout << "Hello world!" << std::endl;
}
return 0;
}
Looping statements
• Such non-terminating while loops are used in real-time systems
that respond to external events:
int main();
int main() {
// @non-terminating@
while ( true ) {
// Wait for an event
// Respond to that event
}
// Technically, we never get here
return 0;
}
Collatz conjecture
• Normally, however, the condition is affected by the action
of the looped block of statements
• We’ll look at one example based on an interesting
mathematical quandary:
• The Collatz conjecture says that if you start with a number a, do the
following:
• If it is odd, multiply it by three and add one
• If it is even, divide it by two
• The Collatz conjecture says that this sequence will ultimately
reduce to the cycle 1, 4, 2, 1, 4, 2, 1, …
Collatz conjecture
• We can try this with any number of initial values
1
2, 1
3, 10, 5, 16, 8, 4, 2, 1
4, 2, 1
5, 16, 8, 4, 2, 1
6, 3, 10, 5, 16, 8, 4, 2, 1
7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1
8, 4, 2, 1
9, 28, 14, 7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1
10, 5, 16, 8, 4, 2, 1
11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1
12, 6, 3, 10, 5, 16, 8, 4, 2, 1
Collatz conjecture
• Write a function collatz_print(…) that takes a positive
integer a and prints out the sequence of integers until it
reaches one, in which case, terminate with "..."
1. Print “a, ”
2. If a ≠ 1,
a. If a is even,
i. Divide a by two,
ii. Otherwise, set a ← 3a + 1
b. Print “a, ”
c. Go to Step 2.
3. Print “…”
Collatz conjecture
• An implementation of this algorithm is:
void collatz_print( unsigned int a );
void collatz_print( unsigned int a ) {
std::cout << a << ", ";
while ( a != 1 ) {
if ( (a % 2) == 0 ) {
a /= 2;
} else {
a = 3*a + 1;
}
std::cout << a << ", ";
}
std::cout << "..." << std::endl;
}
Question: What happens if
the argument passed is 0?
Collatz conjecture
• Try it yourself:
#include <iostream>
#include <cassert>
// Function declarations
void collatz_print( unsigned int a );
// Function definitions
void collatz_print( unsigned int a ) {
assert( a != 0 );
std::cout << a << ", ";
while ( a != 1 ) {
if ( (a % 2) == 0 ) {
a /= 2;
} else {
a = 3*a + 1;
}
std::cout << a << ", ";
}
std::cout << "..." << std::endl;
}
int main() {
collatz_print( 1970 );
return 0;
}
Collatz conjecture
• Mathematicians aren’t so interested in the actual
sequences, but rather the number of terms in the
sequence until you get to 1
• For example,
27, 82, 41, 124, 62, 31, 94, 47, 142, 71, 214, 107, 322, 161, 484, 242, 121, 364, 182, 91, 274, 137,
412, 206, 103, 310, 155, 466, 233, 700, 350, 175, 526, 263, 790, 395, 1186, 593, 1780, 890, 445,
1336, 668, 334, 167, 502, 251, 754, 377, 1132, 566, 283, 850, 425, 1276, 638, 319, 958, 479, 1438,
719, 2158, 1079, 3238, 1619, 4858, 2429, 7288, 3644, 1822, 911, 2734, 1367, 4102, 2051, 6154,
3077, 9232, 4616, 2308, 1154, 577, 1732, 866, 433, 1300, 650, 325, 976, 488, 244, 122, 61, 184, 92,
46, 23, 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1
171, 514, 257, 772, 386, 193, 580, 290, 145, 436, 218, 109, 328, 164, 82, 41, 124, 62, 31, 94, 47,
142, 71, 214, 107, 322, 161, 484, 242, 121, 364, 182, 91, 274, 137, 412, 206, 103, 310, 155, 466,
233, 700, 350, 175, 526, 263, 790, 395, 1186, 593, 1780, 890, 445, 1336, 668, 334, 167, 502, 251,
754, 377, 1132, 566, 283, 850, 425, 1276, 638, 319, 958, 479, 1438, 719, 2158, 1079, 3238, 1619,
4858, 2429, 7288, 3644, 1822, 911, 2734, 1367, 4102, 2051, 6154, 3077, 9232, 4616, 2308, 1154,
577, 1732, 866, 433, 1300, 650, 325, 976, 488, 244, 122, 61, 184, 92, 46, 23, 70, 35, 106, 53, 160,
80, 40, 20, 10, 5, 16, 8, 4, 2, 1
Collatz conjecture
• Write a function collatz(…) that takes a positive integer n and
returns the number of steps required until we get to one:
unsigned int collatz( unsigned int a );
unsigned int collatz( unsigned int a ) {
unsigned int num_iterations{0};
while ( a != 1 ) {
++num_iterations;
if ( (a % 2) == 0 ) {
a /= 2;
} else {
a = 3*a + 1;
}
}
return num_iterations;
}
Collatz conjecture
• Notice the function declarations:
void collatz_print( unsigned int n );
unsigned int collatz( unsigned int n );
• Could we not just give the same name?
• After all, we had other functions with the same name
• Problem: The C++ compiler cannot choose based on
return type only
• The compiler only chooses based on the types of any arguments
• If two functions have identical parameter types, they must have
different names
Collatz conjecture
• We could create a second loop that queries the user for an
argument:
#include <iostream>
int main():
void collatz_print( unsigned int n );
int main() {
bool keep_going{true};
while ( keep_going ) {
unsigned int n{};
std::cout << "Enter a positive integer ('0' to quit): ";
std::cin >> n;
if ( n == 0 ) {
keep_going = false;
} else {
collatz_print( n );
}
}
return 0;
}
Collatz conjecture
• Problem: what happens if we pass our function the argument
0?
• While the specification may require the argument to be greater than
zero, you must explicitly check:
unsigned int collatz( unsigned int n ) {
assert( n >= 1 );
unsigned int num_iterations{0};
// Other code...
return num_iterations;
}
unsigned int collatz( unsigned int n ) {
if ( n == 0 ) {
return 0;
} else {
unsigned int num_iterations{0};
// Other code...
return num_iterations;
}
}
Counting
• Suppose we want a loop to run exactly n times
• Track of how often the loop has executed with a local variable
niterations
1. Initialize a local variable niterations ← 0
2. As long as niterations < n,
a. execute the block of statements associated with the loop,
b. increment niterations, and
c. return to Step 2.
Counting
• Here is a while loop that executes a fixed number of times
• This assumes the value of maxiterations is never changed…
unsigned int num_iterations{0};
while ( num_iterations < max_iterations ) {
// Do something...
++num_iterations;
}
• Once num_iterations == max_iterations, we have
executed the block of statements the required number of
times
Factorial function
• Suppose we want to calculate n!
• Because 0! = 1! = 1, we could start with this value, and then keep
multiplying this by 2, then 3, and so on up until n:
1. Initialize a result r ← 1 and a variable k ← 2
2. If k ≤ n,
a. multiply r by k: r ← kr,
b. increment k ← k + 1, and
c. return to Step 2.
3. Return r
Factorial function
• Here is an implementation of the factorial function:
unsigned int factorial( unsigned int n );
unsigned int factorial( unsigned int n ) {
unsigned int result{1};
unsigned int k{2};
while ( k <= n ) {
result *= k;
++k;
}
return result;
}
How to design a while loop
• Suppose you are attempting to implement an algorithm
where you repeated apply a number of steps
• How do you make the transition from manual to programmatic?
• Recommendation:
• Do the algorithm on paper—in full
• Examine the steps you took, and determine:
• What steps were repeated?
• What condition caused you to stop repeating the steps?
The greatest-common divisor
• From secondary school, you saw that the algorithm for
calculating the greatest common denominator (gcd)
• You are asked to find the gcd of 8008 and 8085
• You first note that 8085 > 8008
• Next, you find that 8085 ÷ 8008 equals 1 with a remainder of 77
• Next, you find that 8008 ÷ 77 equals 104 with a remainder of 0
• From this, you are told that the gcd is 77
The greatest-common divisor
• Let’s try again:
• You are asked to find the gcd of 1583890 and 85800
• You first note that 1583890 > 85800
• Next, you find that 1583890 ÷ 85800 equals 18 with a remainder of 39490
• Next, you find that 85800 ÷ 39490 equals 2 with a remainder of 6820
• Next, you find that 39490 ÷ 6820 equals 5 with a remainder of 5390
• Next, you find that 6820 ÷ 5390 equals 1 with a remainder of 1430
• Next, you find that 5390 ÷ 1430 equals 3 with a remainder of 1100
• Next, you find that 1430 ÷ 1100 equals 1 with a remainder of 330
• Next, you find that 1100 ÷ 330 equals 3 with a remainder of 110
• Next, you find that 330 ÷ 110 equals 3 with a remainder of 0
• From this, you are told that the gcd is 110
The greatest-common divisor
• At each step, we had a pair of numbers
• Call the m and n
• For the initial step, we set
• the larger number to be m, and
• the smaller number to be n
• After that, we repeatedly
• calculated the remainder r when dividing m ÷ n, and
• if r = 0, we are done, and n is the gcd,
• otherwise, we repeat with the pair n and r
• That is, we set m ← n and then we set n ← r
Remember: when you calculate m ÷ n,
the remainder r must always satisfy n > r ≥ 0
The greatest-common divisor
• Let’s look at the first steps:
• At each step, we had a pair of numbers
• Call them m and n
• For the initial step, we set
• the larger number to be m, and
• the smaller number to be n
• Problem: We are doing something if the condition is false:
• We execute a block of statements when m ≥ n is FALSE
• Let’s use the complementary condition:
• This is equivalent to executing the statements when m < n is TRUE
The greatest-common divisor
• Thus, we swap the parameters m and n if m < n
The greatest-common divisor
• The next steps we perform are that we
• calculate the remainder r, and
• if r = 0, we are done, and n is the gcd,
• otherwise, we repeat with the pair n and r
• That is, we set m ← n and then we set n ← r
• Problem: this is not in the form a while loop
The greatest-common divisor
• First, a while loop must return to the condition
• We can repeat the first statement at the end
The greatest-common divisor
• Second, the condition for looping must evaluate to TRUE
• Continuing while r = 0 is FALSE is equivalent to
continuing while r ≠ 0 is TRUE
The greatest-common divisor
• Thus, our final flow chart is:
The greatest-common divisor
• Programming this:
unsigned int gcd( unsigned int m, unsigned int n ) {
The greatest-common divisor
• Programming this:
unsigned int gcd( unsigned int m, unsigned int n ) {
if ( m < n ) {
unsigned int tmp{m};
m = n;
n = tmp;
}
The greatest-common divisor
• Programming this:
unsigned int gcd( unsigned int m, unsigned int n ) {
if ( m < n ) {
unsigned int tmp{m};
m = n;
n = tmp;
}
unsigned int r{m % n};
The greatest-common divisor
• Programming this:
unsigned int gcd( unsigned int m, unsigned int n ) {
if ( m < n ) {
unsigned int tmp{m};
m = n;
n = tmp;
}
unsigned int r{m % n};
while ( r != 0 ) {
}
The greatest-common divisor
• Programming this:
unsigned int gcd( unsigned int m, unsigned int n ) {
if ( m < n ) {
unsigned int tmp{m};
m = n;
n = tmp;
}
unsigned int r{m % n};
while
m
n
r
}
(
=
=
=
r != 0 ) {
n;
r;
m % n;
The greatest-common divisor
• Programming this:
unsigned int gcd( unsigned int m, unsigned int n ) {
if ( m < n ) {
unsigned int tmp{m};
m = n;
n = tmp;
}
unsigned int r{m % n};
while
m
n
r
}
(
=
=
=
r != 0 ) {
n;
r;
m % n;
return n;
}
Infinite loop?
• Question:
• What do you do if you accidentally execute a program that has an
infinite loop?
• Solution:
• In Eclipse, there is a stop button that becomes active when a
program is executing
• Other ides will have similar features
• At the console, press Ctrl-C
Summary
• Following this lesson, you now
• Understand how to implement while loops in C++
• Understand how to limit the number of times the corresponding
statement block is executed
• Seen how to implement various functions requiring looping
statements:
• The Collatz conjecture
• The factorial function
• Understand how to convert a description of an algorithm to one that
you can program
• The example we used was the greatest-common divisor
• Know how to terminate a program in an infinite loop
References
[1]
[2]
[3]
Wikipedia
https://en.wikipedia.org/wiki/While_loop
cplusplus.com
http://www.cplusplus.com/doc/tutorial/control/
tutorialspoint
https://www.tutorialspoint.com/cplusplus/cpp_while_loop.htm
Outline
• In this lesson, we will:
• Describe for loops and their implementation in C++
• Describe their purpose
• Specifically count-controlled loops
Count-controlled loops
• We previous looked at executing a block of code a fixed
number of times:
unsigned int num_iterations{0};
while ( num_iterations < max_iterations ) {
// Do something...
++num_iterations;
}
Count-controlled loops
• This is so common, it is given a short form:
unsigned int k{0};
while ( k < n ) {
// Do something...
++k;
}
for ( unsigned int k{0}; k < n; ++k ) {
// Do something...
}
Count-controlled loops
• This form is called a for loop:
for ( unsigned int k{0}; k < n; ++k ) {
// Do something...
}
Initialization statement
Incremental statement
Conditional expression
• The format gives a clean presentation of a count-
controlled loop
• All you need to know about the loop is on one line
Count-controlled loops
• Behavior:
for ( unsigned int k{0}; k < n; ++k ) {
// Do something...
}
• First, the initialization statement is executed
• Before each execution of the block of statements, the
condition is checked
• If the condition is false, the for loop exits
• After all statements in the block are executed, the
incremental statement is executed as a separate
statement
Count-controlled loops
• If the variable declaration is in the for loop
for ( unsigned int k{0}; k < n; ++k ) {
// The scope of 'k' is this block of statements only
// Do something...
}
• If the declaration is before, the variable must simply be
assigned an initial value for the for loop
unsigned int k{};
for ( k = 0; k < n; ++k ) {
// Do something...
}
// 'k' continues to be in scope
Warning
• Some programming languages have true count-controlled
loops:
• For example, Maple:
for k from 1 to 10 do
% 'k' is assigned a value from 1 to 10
% Do something...
end do;
This loop will iterate exactly ten times, and with each subsequent
execution, the variable k will be assigned the next value
Warning
• In C++, the values of k and n can be changed inside the
body
unsigned int n{10};
for ( unsigned int k{0}; k < n; ++k ) {
if ( (k % 3) == 2 ) {
k += 2;
}
if ( (k % 4) == 1 ) {
++n;
}
std::cout << k << ", " << n << std::endl;
}
Warning
• The output may appear confusing:
unsigned int n{10};
for ( unsigned int k{0}; k < n; ++k ) {
if ( (k % 3) == 2 ) {
k += 2;
}
Output:
0,
1,
4,
7,
10,
10
11
11
11
11
if ( (k % 4) == 1 ) {
++n;
Note that k == n in the last iteration…
}
std::cout << k << ",\t" << n << std::endl;
}
Warning
• In general, don’t do this—use a while loop instead!
unsigned int n{10};
unsigned int k{0};
while ( k < n ) {
if ( (k % 3) == 2 ) {
k += 2;
}
if ( (k % 4) == 1 ) {
++n;
}
std::cout << k << ", " << n << std::endl;
++k
}
Variations on a theme
• The following are identical:
for ( unsigned int k{0}; k < 10; ++k ) {
// 'k' takes on the values, 0, 1, 2, 3, ..., 8, 9
}
for ( unsigned int k{0}; k != n; ++k ) {
// 'k' takes on the values, 0, 1, 2, 3, ..., 8, 9
}
•
The first is more common
Variations on a theme
• Jumping by different values
• For example, jumping by two:
for ( unsigned int k{1}; k < 16; k += 2 ) {
// 'k' takes on the values 1, 3, 5, 7, ..., 15
}
• Going down
• For example, going down by one:
for ( unsigned int k{9}; k > 0; --k ) {
// 'k' takes on the values 9, 8, 7, 6, 5, ..., 1
}
Variations on a theme
• You can jump geometrically:
• For example, multiplying by two
for ( unsigned int k{1}; k < 100; k *= 2 ) {
// 'k' takes on 1, 2, 4, 8, 16, 32, 64
}
• You can shrink geometrically:
for ( unsigned int k{100}; k > 0; k /= 2 ) {
// 'k' takes on 100, 50, 25, 12, 6, 3, 1
}
Variations on a theme
• You can even use floating-point numbers:
for ( double x{0.0}; x <= 1.0; k += 0.1 ) {
// 'x' takes on 0.0, 0.1, 0.2, ..., 0.9, 1.0
}
• Problem: floating-point numbers are not exact:
for ( double x{0.0}; x <= 1.0; k += 1.0/9.0 ) {
// 'x' takes on 0, 0.111111, 0.222222, 0.333333,
//
..., 0.666667, 0.777778, 0.888889
}
Factorial function
• Here is an implementation of the factorial function:
unsigned int factorial( unsigned int n );
unsigned int factorial( unsigned int n ) {
unsigned int result{1};
for ( unsigned int k{2}; k <= n; ++k ) {
result *= k;
}
}
return result;
If n < 2, the body of the loop is never executed
Factorial function
• Try this yourself:
#include <iostream>
// Function declarations
int main();
unsigned int factorial( unsigned int n );
// Function definitions
int main() {
for ( int k{0}; k < 20; ++k ) {
std::cout << k << "! = " << factorial( k ) << std::endl;
}
return 0;
}
unsigned int factorial( unsigned int n ) {
unsigned int result{1};
for ( unsigned int k{2}; k <= n; ++k ) {
result *= k;
}
return result;
}
Perfect numbers
• A number is perfect—whatever that means—if it is the sum of
its divisors
bool is_perfect( unsigned int n );
bool is_perfect( unsigned int n ) {
unsigned int sum{0};
for ( unsigned int k{1}; k < n; ++k ) {
if ( (n % k) == 0 ) {
sum += k;
}
}
return (sum == n);
}
Prime numbers
• A number n is prime if it is not divisible by any number
between 2 and n – 1:
bool is_prime( unsigned int n );
bool is_prime( unsigned int n ) {
for ( unsigned int k{2}; k < n; ++k ) {
if ( (n % k) == 0 ) {
return false;
}
}
return true;
}
Prime numbers
• You really only need to search up to the integer square root of
n:
bool is_prime( unsigned int n );
bool is_prime( unsigned int n ) {
unsigned int upper_bound{isqrt(n)};
for ( unsigned int k{2}; k <= upper_bound; ++k )
{
if ( (n % k) == 0 ) {
return false;
}
}
return true;
}
Summary
• Following this lesson, you now
• Understand how to implement for loops in C++
• Know this is a special case of the while loop
• Understand it should be restricted to count-controlled loops
• Seen various applications
References
[1]
Wikipedia
https://en.wikipedia.org/wiki/For_loop
Download