540 likes | 738 Views
Controlling statement execution. CS101 2012.1. Statement block. A block looks like {statement;statement;…statement;} 0 or 1 statement allowed for uniformity Walk down the list executing one statement after another Effect of each statement on memory completes before next executed
E N D
Controlling statement execution CS101 2012.1
Statement block • A block looks like{statement;statement;…statement;} • 0 or 1 statement allowed for uniformity • Walk down the list executing one statement after another • Effect of each statement onmemory completesbefore next executed • Note on scope: Outside {…} cannot use variables declared inside float x = 5, y = 11; float temporary = x; x = y; y = temporary; CS101 2012.1
If-then-else int a, b; cin >> a; if (a >= 0) { b = a; } else { b = -a; } • Store in variable b the absolute value of variable a • Store in variable c the smaller of the values of variables a and b • Else part is optional • Cascades/nests allowed • Statement blocks also optional but best used int a, b, c; cin >> a >> b; if (a < b) { c = a; } else { c = b; } CS101 2012.1
Example: withdrawing money from bank cin >> deduct; if (deduct > balance) { cout << “Account overdrawn\n”; } else { cout << “Successfully withdrawing ” << deduct << endl; balance -= deduct; // emit paper money } CS101 2012.1
Curly brackets • You can also write then or else parts without curly brackets, but this could be dangerous • Best to always use curly brackets even if not needed int m = 5; int n = 10; if (m >= n) ++m; ++n; cout << "m=" << m << "n=" << n << endl; Increment of n happens outside the if-then action, which only increments m CS101 2012.1
Conditional expression • Format: cond ? ifExpr : elseExpr • Earlier examples rewritten • b = (a > 0)? a : -a; • c = (a < b)? a : b; • If in doubt, use (parens) to make sure expression tree is correct • Nesting quickly gives unreadable code:(a > 0)? a : ((-a < b)? 100+c : c-100) CS101 2012.1
Switch statement • if (cond1) {…} else if (cond2) {…} else if (cond3) {…} can get tiring • Common use is to choose between different statements depending on the value of a variable Can be char, int, long int switch (dayOfWeek) { case 0: cout << “Sunday”; break; case 6: cout << “Saturday”; break; default: cout << “Weekday”; } If no break here, control will “fall through” to the next case If none of the listed cases match dayOfWeek CS101 2012.1
Switch mystery int val = 5; switch (val) { case 5: cout << "five\n"; // suppose we forget this break; case 4: cout << "four\n"; break; default: cout << "default\n"; } This statement will be executed even though val is not 4 CS101 2012.1
Switch example switch (ch) { case 'a': case 'A': case 'e': case 'E': case 'i': case 'I': case 'o': case 'O': case 'u': case 'U': cout << ch << " is a vowel" << endl; break; default: cout << ch << " is not a vowel" << endl; } Can use fall-through as a feature to combine many cases CS101 2012.1
Another switch example cout << "Enter simple expression: "; int left; int right; char operator; cin >> left >> operator >> right; cout << left << " " << operator << " " << right << " = "; switch (operator) { case '+' : cout << left + right << endl; break; case '-' : cout << left - right << endl; break; case '*' : cout << left * right << endl; break; case '/' : cout << left / right << endl; break; default: cout << "Illegal operation" << endl; } CS101 2012.1
The infinite loop while (true) { cout << “I will lecture clearly and slowly\n”; cout << “I will remain quiet in class\n”; } Insanity: doing the same thing over and over again and expecting different results. Albert Einstein CS101 2012.1
Are inputs in increasing order? • Keep reading input number for ever, and check if it is greater than the previous number read #include <iostream> #include <limits> using namespace std; double prev = numeric_limits<double>::min(); while (true) { double cur; cin >> cur; if (cur <= prev) { cout << “Not in increasing order\n”; } prev = cur; } How do we get out of the infinite loop? CS101 2012.1
Printing an integer in binary • Surprisingly, standard C++ does not offer a library function • But simple enough • For brevity consider printing a byte num • Take bit pattern mask = 10000000 • Bitwise and: num & mask • If result is nonzero, print ‘1’ else ‘0’ • Shift mask right to 01000000, then 00100000, 00010000, etc. CS101 2012.1
Shortcut • Instead of shifting mask right, shift num left • Use fixed mask of 10000000 • Say num = 01101011 = 107 (decimal) • 10000000 & 01101011 print ‘0’ • Shift num left to 11010110 • 10000000 & 11010110 print ‘1’ • Shift num left to 10101100 • 10000000 & 10101100 print ‘1’ • And so on CS101 2012.1
Raising a number to an integer power • Given a double base and a non-negative integer power int pow • Find basepow • A simple and a more efficient version double ans = 1; int todo = pow; while (todo > 0) { ans = ans * base; // or ans *= base; --todo; } CS101 2012.1
Loop invariant • Initially, ans=1 and todo=pow • After each iteration, ans * basetodo = basepow • ans multiplied by base, todo reduced by 1 • Finally, todo=0, therefore ans = basepow • Number of multiplications: pow double ans = 1; int todo = pow; while (todo > 0) { ans = ans * base; // or ans *= base; --todo; } CS101 2012.1
The squaring method • Suppose pow = 32 • Instead of base*base*…*base(31 multiplications), run the following double b2 = base * base; double b4 = b2 * b2; double b8 = b4 * b4; double b16 = b8 * b8; double ans = b16 * b16; // only 5 multiplications CS101 2012.1
General powers • Suppose pow = 29 is a byte • Express as 1 + 4 + 8 + 16 • Answer is base * b4 * b8 * b16 • Let bx take values 0 through 7 • Keep squaring base as before • If the bxth bit of pow is 1, include the power of base in the product, else not • Already know how to get bit by (val & 1) bx CS101 2012.1
Faster code unsigned int todo = pow; double ans = 1, term = base; while (todo > 0) { if (todo & 1 == 1) { ans *= term; } term = (term * term); // squaring todo = (todo >> 1); } What if pow is a real number? Exercise: Work out the loop invariant CS101 2012.1
Factorial long long int double fac = 1, n; cin >> n; while (n > 0.5) { fac *= (n--); } cout << fac << endl; • Can easily overflow even for moderate n • Even if we use double CS101 2012.1
Iteration: Approximating the logarithm • How many times must we divide a number x by 10 until the result goes below 1? • while (condition) statementOrBlock Another shorthand: x /= 10; float x; cin >> x; int numDivs = 0; while (x > 1) { x = x / 10; numDivs = numDivs + 1; } cout << numDivs; Prolog Loopbody More shorthands: numDivs += 1; or ++numDivs; Epilog CS101 2012.1
Quick review • Why do we care about how data types are represented in RAM? • To understand the limits of what can be represented within hardware limitations • Thus write more reliable and robust code • Can give insights for better algorithms • E.g., bit shifts squaring trick fast power algorithm CS101 2012.1
Perimeter of regular polygons • Polygons inscribed in circle of radius ½ • First, a polygon with sides x • Next double the number ofsides, each side is y • Let’s start with x = ½ (six sides) CS101 2012.1
Code double sides = 6, x = .5; while (true) { cout << (sides * x) << endl; double a = sqrt(1-x*x) / 2; double b = .5 – a; double y = sqrt(x*x/4 + b*b); x = y; sides *= 2; } CS101 2012.1
Numerical integration • Divide x-axis into intervals of width h • Approximate area under function f(x) between x and x+h as h f(x) • As h becomes smaller, estimate should become more accurate • But remember finite precision limitations CS101 2012.1
One loop nested in another double h = .01; while (true) { double area = 0, x = -1.; while (x + h <= 1.) { area += h * sqrt(1. – x*x); x += h; } cout << 2.*area << endl; h /= 2.; // halve interval width } CS101 2012.1
Moral of the story • On an ideal computer, increasing number of polygon sides, or decreasing interval width h without bound should get you better and better estimates • Finite precision prevents this • (This is why we need to know our hardware representation!) • In general limits are troublesome to evaluate reliably • Luckily there are other methods, e.g., convergent series CS101 2012.1
ex • Well-known series double ans=1, base=x, fac=1, ix=1; bool keepGoing = true; while (keepGoing) { ans += base/fac; base *= x; fac *= (++ix); if (base/fac < epsilon) { keepGoing = false; } } Tedious to have to exit from a loop like this CS101 2012.1
break while (true) { ans += base/fac; base *= x; fac *= (++ix); if (base/fac < epsilon) { break; } cout << (base/fac) << endl; } Terminates immediately enclosing while loop CS101 2012.1
Pep • Why are we developing algorithms to compute powers of numbers or or ex if we already have library functions? • Techniques like limits, numerical integration, series summing are universal • Familiarizes us with loop and break constructs CS101 2012.1
A counting problem • Input is int len • How many sequences of len bits are there? • 2len • Of these, how many do not have two consecutive zeros? • If len = 1, answer is 2 (0, 1) • If len = 2, answer is 3 (01, 10, 11) • Suppose a(len) sequences end with 0 • And b(len) sequences end with 1 • Required answer is a(len) + b(len) CS101 2012.1
Counting problem, continued • If a sequence ends with 0, second last bit must be 1 • Therefore a(len) = b(len-1) • If a sequence ends with 1, second last bit could be either 0 or 1 • b(len) = a(len-1)+b(len-1) • Therefore b(len) = b(len-2)+b(len-1) • First focus only on b(len) • Hemachandra numbers, Fibonacci series CS101 2012.1
Base cases for b() • b(1) = 1 (the bit sequence 1) • b(2) = 2 (sequences 01, 11) int len; cin >> len; if (len == 1 || len == 2) { cout << “b(" << len << ")=" << len; } else { … } CS101 2012.1
After base cases • Note that b(len) depends only on b(len-1) and b(len-2) • Enough to keep around last two values • Rather than all of b(1), b(2), …, b(len) lx lx 1 2 3 5 1 2 3 5 8 bLx bLx bLxM2 bLxM1 bLxM2 bLxM1 CS101 2012.1
Else… len 3 int bLxM2=1, bLxM1=2; int lx = 3; while (lx < len) { int bLx = bLxM2 + bLxM1; // shift forward one step ++lx; bLxM2 = bLxM1; bLxM1 = bLx; } cout << len << " " << (bLxM2+bLxM1) <<endl; Invariant:bLxM2+bLxM1 = b(lx) CS101 2012.1
Running average • The user inputs a sequence of numbers • After the third number is input, and for every subsequent input, print the three-point running average double a1, a2, a3; cin >> a1 >> a2 >> a3; while (true) { cout << (a1 + a2 + a3) / 3.; a1 = a2; a2 = a3; cin >> a3; } CS101 2012.1
Migrations between Mumbai and Pune • Initial populations m and p • Every year, 1/4th of Mumbai migrates to Pune • And ½ of Pune migrates to Mumbai • Simulate for k years • Do the populations stabilize? CS101 2012.1
Migrations code main() { double m, p; int k; cin >> m >> p >> k; for (int t=0; t<k; ++t) { p = p – p/2. + m/4.; m = m – m/4. + p/2.; // print } } X Synchronous vs. asynchronous update CS101 2012.1
Greatest common divisor (gcd) • Given integers m n 1, find their gcd • gcd(m,n) = gcd(n, m%n) int m, n; cin >> m >> n;// assume m >= n while (n > 0) { const int tmp = n; n = m % n; m = tmp; } cout << m << endl; • Let h = gcd(m,n) • h divides m, n • Let m = n*q + r • Given h divides n … • … h must divide r • h divides gcd(n,r) (so h gcd(n,r)) • Also, gcd(n,r) dividesn and r, n and m • h gcd(n,r) CS101 2012.1
“String theory” • Iterative computations are demonstrated well on arrays • We have already introduced strings, which are arrays of characters • Luckily the system manages the array space for us • Can assign and append to strings • Can read a position: cout << message[px] • Can write a position: message[px] = ‘q’ • That’s all we need for now CS101 2012.1
Printing a string in reverse string message; getline(cin, message); int mx = message.size()-1; while (mx >= 0) { cout << message[mx]; --mx; } • mx updated in a completely predictable way • Ideal candidate to write as for loop Character at position mx in string message CS101 2012.1
While and for for (init; cond; stepper) { stmt } while (cond) { stmt } init f cond cond f t t stmt stmt stepper CS101 2012.1
Printing reversed string, for loop • General syntaxfor (prelude; condition; stepper) { body } • Equivalent toprelude; while (condition) { body; stepper; } for (int mx = message.size()-1;mx >= 0; --mx) { cout << message[mx]; } Look, a declaration In ISO standard C++, mx is no longer available here CS101 2012.1
Nested for loops • Calculate (again!) by… • Generate grid of x, y points in the plane for (double x=-radius; x<=radius; ++x) { for (double y=-radius; y<=radius; ++y) { // detect if they are within a circular disk } } • Just to demonstrate nested for loops • radius2 grid points unacceptably slow • Numerical integration much faster, at least as accurate CS101 2012.1
Finding needles in a haystack • Given two strings, needles and haystack • needles has no repeated characters • haystack may repeat characters • How many characters in needles appear in haystack at least once? • needles = “bat”, haystack = “tabla” 3 • needles = “tab”, haystack = “bottle” 2 CS101 2012.1
One needle in a haystack • Subproblem: given one character ch and a string find if ch appears in string at least once char ch; // suitably initialized string haystack; // suitably initialized int ans = 0; // will change to 1 if found for (int hx = 0; hx < haystack.size(); ++hx) { if (ch == haystack[hx]) { ++ans; break; // quit on first match } } CS101 2012.1
Many needles: nested loop main() { string needles, haystack; getline(cin, needles); getline(cin, haystack); int ans = 0; for (int nx=0; nx < needles.size(); ++nx) { char ch = needles[nx]; for (int hx = 0; hx < haystack.size(); ++hx) { if (ch == haystack[hx]) { ++ans; break; // quit on first match } } // ends haystack loop } // ends needles loop } Generalize to work in case needles can also have repeated characters CS101 2012.1
Duplicate needles • needles = “bat”, haystack = “tabla” 3 • needles = “tab”, haystack = “bottle” 2 • needles = “bata”, haystack = “tabla” 3 • Two approaches • Dedup needles before executing earlier code (reducing to known problem) • Dedup needles “on the fly” (inside the nx loop) Exercise: If the input strings have n and h characters, at most how much time does the needle-in-haystack search code take? CS101 2012.1
Parallel steppers • Print the first character of a string, then the last, then second, then second last … until you meet in the middle for (int lx=0, rx=message.size()-1;lx < rx; ++lx, --rx) { cout << message[lx] << message[rx]; } Parallel steppers Middle character of odd-length string will not get printed CS101 2012.1
lx rx H e l l o lx rx o e l l H lx,rx o l l e H Reversing a string for (int lx=0, rx=msg.size()–1;lx < rx; ++lx, --rx) { const char tmp = msg[lx]; msg[lx] = msg[rx]; msg[rx] = tmp; } Used as lhs, msg[rx] is a cell where a character is to be written Used in a rhs expression, msg[lx] is a character value CS101 2012.1