520 likes | 778 Vues
Announcements. Homework 3 is due this Wednesday, November 11 th Superman robot moves into the phone booth. Homework 4 will be assigned this week and will be due next Wednesday, November 18 th First Midterm On November 21 st Saturday at 9:00am (~ 100 minutes). From Selection to Repetition.
E N D
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; }
true true test test false false Statement list Next statement Statement list Next statement Semantics of while loop if (test) while (test) { { statement list; statement list; } }
Sum Example: why we need loops? • We want to find the sum of 10 positive values • We can write: int num1, num2, num3, num4, num5; int sum; cin >> num1 >> num2 >> num3 >> num4 >> num5; sum = num1 + num2 + num3 + num4 + num5; cin >> num1 >> num2 >> num3 >> num4 >> num5; sum += 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; // this program piece int i = 1; // calculates the sum of while (i <= 10) // integers between and { // including 1 and 10 sum = sum + i; i += 1; }
Walkthrough of the example 1 2 i 0 1 sum i<=10 true false sum=sum+i; i=i+1; cout<<sum; int sum = 0; int i = 1; while (i <= 10) { sum = sum + i; i = i + 1; } cout << sum;
Walkthrough of the example 2 3 i 1 3 sum i<=10 true false sum=sum+i; i=i+1; cout<<sum; int sum = 0; int i = 1; while (i <= 10) { sum = sum + i; i = i + 1; } cout << sum;
Walkthrough of the example 3 4 i 3 6 sum i<=10 true false sum=sum+i; i=i+1; cout<<sum; int sum = 0; int i = 1; while (i <= 10) { sum = sum + i; i = i + 1; } cout << sum;
Walkthrough of the example 10 11 i 45 55 sum i<=10 true false sum=sum+i; i=i+1; cout<<sum; int sum = 0; int i = 1; while (i <= 10) { sum = sum + i; i = i + 1; } cout << sum;
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 andloop test (before the loop) • No general rule. Theway of initializationandtheinitialvaluesareto be determinedaccordingtotheapplication • 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 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; } } // for loop alternative 3 int len; int k; len = s.length(); k = 0; for(; k < len; k+= 1) { 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 revstringto 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 • for (inti = 10; i < 5; i++) { cout << "How many times do I print?"; } • for (inti = 10; i >= 1; i++) { cout << "How many times do I print?"; } • inti = 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 anotherreason
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 productis 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 numberis 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>; <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 ); Don’t forget
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 usebreakin 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 power = 1; int n, m; cin >> n >> m; for (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 (intnumstars) // pre: numstars > 0 // post: displays numstars stars in one line { inti; 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() { inti,k,numlines; const intWIDTH = 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