Lecture 6: Functions II PDF
Document Details
Uploaded by FervidDune
ETH Zurich
Tags
Related
Summary
This is an educational presentation about programming concepts in computer science. It covers preconditions and postconditions, functions in C++ and how to implement them. Stepwise refinement is emphasized.
Full Transcript
10. Functions II Pre- and Postconditions, Stepwise Refinement, Scope, Libraries and Standard Functions 253 Preconditions precondition: what is required to hold when the function is called? defines the domain of the function...
10. Functions II Pre- and Postconditions, Stepwise Refinement, Scope, Libraries and Standard Functions 253 Preconditions precondition: what is required to hold when the function is called? defines the domain of the function ⇒ value 0e is undefined for e < 0 // PRE: e >= 0 || b != 0.0 double pow(double b, int e){... } 254 Postconditions postcondition: What is guaranteed to hold after the function call? Specifies value and effect of the function call. // PRE: e >= 0 || b != 0.0 // POST: return value is b^e double pow(double b, int e){... } Here only value, no effect. 255 Pre- and Postconditions should be correct: if the precondition holds when the function is called then also the postcondition holds after the call. Funktion pow: works for all numbers b ̸= 0 256 Pre- and Postconditions We do not make a statement about what happens if the precondition does not hold. C++-standard-slang: “Undefined behavior”. Function pow: division by 0 257 Pre- and Postconditions pre-condition should be as weak as possible (largest possible domain) post-condition should be as strong as possible (most detailed information) 258 White Lies... // PRE: e >= 0 || b != 0.0 // POST: return value is b^e is formally incorrect : Overflow if e or b are too large be potentially not representable as a double (holes in the value range!) 259 White Lies are Allowed // PRE: e >= 0 || b != 0.0 // POST: return value is b^e The exact pre- and postconditions are platform-dependent and often complicated. We abstract away and provide the mathematical conditions. ⇒ compromise between formal correctness and lax practice. 260 Limits of Correctness Recommendation Of course, and somewhat unfortunately, there is a gray area here and we advocate to apply common sense such that pre- and post-conditions are helpful. Do not over-engineer but also do not become careless. Document functions such that your later ego or someone else under- stands what the function does under which preconditions, within rea- sonable limits. 261 Checking Preconditions... Preconditions are only comments. How can we ensure that they hold when the function is called? 262... with assertions #include... // PRE: e >= 0 || b != 0.0 // POST: return value is b^e double pow(double b, int e) { assert (e >= 0 || b != 0); double result = 1.0;... } 263 Asserts: Syntax and Semantics assert ( expression ) expression: Expression that can be converted to bool.. Semantik: If expression == true: no effect. If expression == false: Program is halted with error message. requires #include 264 Postconditions with Asserts The result of “complex” computations is often easy to check. Then the use of asserts for the postcondition is worthwhile. // PRE: the discriminant p*p/4 - q is nonnegative // POST: returns larger root of the polynomial x^2 + p x + q double root(double p, double q) { assert(p*p/4 >= q); // precondition double x1 = - p/2 + sqrt(p*p/4 - q); assert(equals(x1*x1+p*x1+q,0)); // postcondition return x1; } 265 Assertions for the gcd(x, y) Check if the program is on track... // Input x and y std::cout > x; Input arguments for calcula- std::cout > y; // Check validity of inputs assert(x > 0 && y > 0); Precondition for the ongoing computation... // Compute gcd(x,y), store result in variable a 266 Assertions for the gcd(x, y)... and question the obvious!...... assert(x > 0 && y > 0); Precondition for the ongoing computation... // Compute gcd(x,y), store result in variable a assert (a >= 1); assert (x % a == 0 && y % a == 0); Properties of the for (int i = a+1; i 0); // Ignored... // Compute gcd(x,y), store result in variable a assert(a >= 1); // Ignored... 270 Stepwise Refinement A simple technique to solve com- plex problems Niklaus Wirth. Program development by stepwise refinement. Commun. ACM 14, 4, 1971 271 Stepwise Refinement Solve the problem step by step. Start with a coarse solution on a high level of abstraction (only comments and abstract function calls) At each step, comments are replaced by program text, and functions are implemented (using the same principle again) The refinement also refers to the development of data representation (more about this later). If the refinement is realized as far as possible by functions, then partial solutions emerge that might be used for other problems. Stepwise refinement supports (but does not replace) the structural understanding of a problem. 272 Example Problem Find out if two rectangles overlap! 273 Coarse Solution (include directives omitted) int main() { // input rectangles // overlap? // output solution return 0; } 275 Refinement 1: Input Rectangles h1 (x1 , y1 , w1 , h1 ) (x1 , y1 ) w1 y (x2 , y2 , w2 , h2 ) h2 (x2 , y2 ) w2 x 276 Refinement 1: Input Rectangles Width w and height h may be negative. h≥0 (x, y, w, h) w x1 >> y1 >> w1 >> h1; int x2, y2, w2, h2; std::cin >> x2 >> y2 >> w2 >> h2; // overlap? // output solution return 0; } 278 Refinement 2: Overlap? and Output int main() { input rectangles ✓ bool overlap = rectangles_overlap(x1,y1,w1,h1,x2,y2,w2,h2); if (overlap) std::cout b // POST: returns true if [a1, b1],[a2, b2] overlap bool intervals_overlap(int a1, int b1, int a2, int b2) { return max(a1, b1) >= min(a2, b2) && min(a1, b1) y) return x; else return y; } already exists in the standard library // POST: the minimum of x and y is returned int min(int x, int y){ if (xb // POST: returns true if [a1, b1],[a2, b2] overlap bool intervals_overlap(int a1, int b1, int a2, int b2) { return std::max(a1, b1) >= std::min(a2, b2) && std::min(a1, b1) > x1 >> y1 >> w1 >> h1; // POST: returns true if [a1, b1],[a2, b2] overlap int x2, y2, w2, h2; bool intervals_overlap(int a1, int b1, int a2, int b2) std::cin >> x2 >> y2 >> w2 >> h2; { bool clash = rectangles_overlap(x1,y1,w1,h1,x2,y2,w2,h2); return std::max(a1, b1) >= std::min(a2, b2) if (clash) && std::min(a1, b1)