340 likes | 355 Views
ICOM 4015 Advanced Programming. Lecture 2 Procedural Abstraction Reading: LNN Chapter 4, 14. Prof. Bienvenido Velez. Procedural Abstraction Topics. Topic 1 Functions as abstract contracts Parameter passing Scoping Topic 2 Functional arguments Topic 3 Top-down modular design
E N D
ICOM 4015 Advanced Programming Lecture 2 Procedural Abstraction Reading: LNN Chapter 4, 14 Prof. Bienvenido Velez ICOM 4015 - Lecture 2
Procedural AbstractionTopics • Topic 1 • Functions as abstract contracts • Parameter passing • Scoping • Topic 2 • Functional arguments • Topic 3 • Top-down modular design • Stepwise refinement • Topic 4 • Recursive functions • Recursion vs. Iteration • Topic 5 • Further procedural abstraction • Function overloading and templates ICOM 4015 - Lecture 2
Procedural Abstraction I Outline • Functions as abstract contracts • Value/Reference parameters • Procedural Abstraction Defined • Scope Rules ICOM 4015 - Lecture 2
Example 0Finding the roots of ax2 +bx + c #include <cmath> // roots(a, b, c, r1, r2) - returns the number of // real roots of ax^2 + bx + c. If two roots exists // they are returned is r1 and r2. If only one root // exists, it is returned in r1. Otherwise the value // of r1 and r2 is undetermined. int roots(float a, float b, float c, float& r1, float& r2) { float d = b * b - 4.0 * a * c; if (d < 0) { return 0; } r1 = (-b + sqrt(d)) / (2.0 * a); if (d == 0) { return 1; } r2 = (-b - sqrt(d)) / (2.0 * a); return 2; } WHAT? formal parameters HOW? roots.cc definitions int roots(float a, float b, float c,float& r1, float& r2); roots.h declarations ICOM 4015 - Lecture 2
Procedural Abstraction • A function should accomplish ONEwell defined and easy to remember task • A function establishes a contract between callers and implementers • The implementer may select any implementation that satisfies the contract. • The contract should specify WHAT task the function accomplishes, NOT HOW it accomplishes it “HOW” is hidden or abstracted out, hence the name procedural abstraction ICOM 4015 - Lecture 2
Scope Rules &Parameter Passing Mechanisms #include <iostream> // Forward definitions int f(int& x); // Global definitions static int x = 0; int y = 0; int main() { for (int i=0; i < 5; i++) { int arg = x; int r = f(x); cout << " f(" << arg << ") -> " << r; cout << " Glob x=" << x << endl; cout << " Glob y=" << y << endl; } } int f(int& x) { int y=0; static int z=0; y++; z+=2; x = y + z; cout << " Loc x=" << x; cout << " Loc y=" << y; cout << " Loc z=" << z; return z; } Global in Module Global Local to For Loop Local to Block Local to Function [bvelez@amadeus] ~ >> scope1 Loc x=3 Loc y=1 Loc z=2 f(0) -> 2 Glob x=3 Glob y=0 Loc x=5 Loc y=1 Loc z=4 f(3) -> 4 Glob x=5 Glob y=0 Loc x=7 Loc y=1 Loc z=6 f(5) -> 6 Glob x=7 Glob y=0 Loc x=9 Loc y=1 Loc z=8 f(7) -> 8 Glob x=9 Glob y=0 Loc x=11 Loc y=1 Loc z=10 f(9) -> 10 Glob x=11 Glob y=0 [bvelez@amadeus] ~ >> ICOM 4015 - Lecture 2
Diagramas de Bloques x: y: main: for: i: arg: r: f: x: y: z: ICOM 4015 - Lecture 2
Procedural Abstraction ISummary of Concepts • Value parameters – changes remain local to function. Function works with a copy of the argument. • Reference parameters – changes propagate to argument. Function works with original argument. • Procedural abstraction – a function establishes a contract with its callers on what it accomplishes, hiding how it accomplishes it. ICOM 4015 - Lecture 2
Procedural Abstraction I - ScopingSummary of Concepts II • Definition: Scope of a declaration • region of code where declaration is active • Scope rules allow better control over the namespace • Local namespaces (e.g. functions, blocks) independent of each other • Local declarations take precedence over global declarations ICOM 4015 - Lecture 2
Procedural Abstraction II Outline • Procedural arguments ICOM 4015 - Lecture 2
IntegrationWithout Procedural Arguments #include <iostream> // Forward definitions double integrateSqr(double a, double b, double n); double integrateCube(double a, double b, double n); int main() { cout << "Integral of x^2 in [0,1] = " << integrateSqr(0.0, 1.0, 10000) << endl; cout << "Integral of x^3 in [0,1] = " << integrateCube(0.0, 1.0, 10000) << endl; } double integrateSqr(double a, double b, double n) { double delta = (b-a) / double(n); double sum = 0.0; for (int i=0; i<n; i++) { float x = a + delta * i; sum += x * x * delta; } return sum; } double integrateCube(double a, double b, double n) { double delta = (b-a) / double(n); double sum = 0.0; for (int i=0; i<n; i++) { float x = a + delta * i; sum += x * x * x * delta; } return sum; } [bvelez@amadeus] ~/icom4015/lec05 >> example2 Integral of x^2 in [0,1] = 0.333283 Integral of x^3 in [0,1] = 0.24995 [bvelez@amadeus] ~/icom4015/lec05 >> ICOM 4015 - Lecture 2
Example 3 IntegrationWith Procedural Arguments #include <iostream> // Forward definitions double integrate(double a, double b, double n, double f(double x)); double cube(double x); double sqr(double x); int main() { cout << "Integral of x^2 in [0,1] = " << integrate(0.0, 1.0, 10000, sqr) << endl; cout << "Integral of x^3 in [0,1] = " << integrate(0.0, 1.0, 10000, cube) << endl; } double integrate(double a, double b, double n, double f(double x)) { double delta = (b-a) / double(n); double sum = 0.0; for (int i=0; i<n; i++) { sum += f(a + delta * i) * delta; } return sum; } double cube(double x) { return x * x * x; } double sqr(double x) { return x * x; } [bvelez@amadeus] ~/icom4015/lec05 >> example2 Integral of x^2 in [0,1] = 0.333283 Integral of x^3 in [0,1] = 0.24995 [bvelez@amadeus] ~/icom4015/lec05 >> ICOM 4015 - Lecture 2
Procedural Abstraction IIFunctional ArgumentsSummary of Concepts • Functional arguments • Allow abstraction over processes and functions ICOM 4015 - Lecture 2
Procedural Abstraction III Outline • Top-down stepwise refinement ICOM 4015 - Lecture 2
Step 0 - Outline // top-down.cc // Computes weighted average score of grades. Grades // include two assignments two midterm exams and one final exam. // All grades are input from standard input, but the weights of // each type of grade are hard coded. // C header files extern "C" { } // Standard C++ header files #include <iostream> // My own C++ header files // Macro definitions // Forward definitions of auxiliary functions // Global declarations // Main function int main() { // Read assignment grades // Read exam grades // Read final exam grade // Calculate average // Print report return 0; } // Auxiliary functions ICOM 4015 - Lecture 2
Step 1 – Code + Stubs int main() { float assignment1, assignment2; float exam1, exam2; float finalExam; readAssignmentGrades(assignment1, assignment2); readExamGrades(exam1, exam2); readFinalGrade(finalExam); float avg; avg = calculateAverage(assignment1, assignment2, exam1, exam2, finalExam); printReport(assignment1, assignment2, exam1, exam2, finalExam, avg); return 0; } // Auxiliary functions void readAssignmentGrades(float& assignment1, float& assignment2) {} void readExamGrades(float& ex1, float& ex2) {} void readFinalGrade(float& final) {} float calculateAverage(float assignment1, float assignment2, float exam1, float exam2, float finalExam) {} void printReport(float assignment1, float assignment2, float exam1, float exam2, float finalExam, float average) {} ICOM 4015 - Lecture 2
Step 2 - Refine // Auxiliary functions void readAssignmentGrades(float& assignment1, float& assignment2) { // Read a float in [0,100] into assignment1 // Read a float in [0,100] into assignment2 } void readExamGrades(float& ex1, float& ex2) { // Read a float in [0,100] into ex1 // Read a float in [0,100] into ex2 } void readFinalGrade(float& final) { // Read a float in [0,100] into final } float calculateAverage(float assignment1, float assignment2, float exam1, float exam2, float finalExam) { // Calculate assignments average // Calculate exams average // Calculate weighted average } void printReport(float assignment1, float assignment2, float exam1, float exam2, float finalExam, float average) { // print assignment grades // print exam grades // print final exam grades // print weighted average } ICOM 4015 - Lecture 2
Top-down stepwise refinement cycle outline refine code + stubs ICOM 4015 - Lecture 2
Procedural Abstraction IIITop-down design – Stepwise RefinementSummary of Concepts • Top-Down design / stepwise refinement • A cyclic development technique • Each cycle adds a level of detail to the code • We have a functioning (although incomplete) program after every iteration of the process ICOM 4015 - Lecture 2
Procedural Abstraction IV Outline • Recursive Functions • Activation records, call stacks • Expressiveness of recursion vs. iteration • Efficiency concerns • function call overhead • duplication of work • process complexity ICOM 4015 - Lecture 2
Example 0Factorials // factorials.cc // Implements recursive and interative versions of algorithms for // computing the factorial (N!) of a number. // Standard C++ header files #include <iostream> // Forward definitions of auxiliary functions long recFactorial(long n); long iterFactorial(long n); int main() { long number; while(true) { cout << "Please enter a positive number (or negative to end): "; cin >> number; if (number < 0) return 0; cout << "Recursive: " << number << "! = " << recFactorial(number) << endl; cout << "Iterative: " << number << "! = " << iterFactorial(number) << endl; } } long recFactorial(long n) { if (n==0) { return 1; } else { return (n * recFactorial(n - 1)); } } long iterFactorial(long n) { long product = 1; for (long i=1; i<=n; i++) { product *= i; } return product; } [bvelez@amadeus] ~/icom4015/lec07 >>factorials Please enter a positive number (or negative to end): 3 Recursive: 3! = 6 Iterative: 3! = 6 Please enter a positive number (or negative to end): 4 Recursive: 4! = 24 Iterative: 4! = 24 Please enter a positive number (or negative to end): 5 Recursive: 5! = 120 Iterative: 5! = 120 Please enter a positive number (or negative to end): 6 Recursive: 6! = 720 Iterative: 6! = 720 Please enter a positive number (or negative to end): -1 [bvelez@amadeus] ~/icom4015/lec07 >>fibonacci ICOM 4015 - Lecture 2
Example 1Fibonacci Numbers // fibonacci.cc // Iterative and recursive algorithms for computing Fibonacci numbers ... // Auxiliary Functions long recFibonacci(long n) { if (n==0) { return 0; } else if (n==1) { return 1; } else { return (recFibonacci(n-1) + recFibonacci(n-2)); } } long iterFibonacci(long n) { if (n==0) { return 0; } else if (n==1) { return 1; } long F0 = 0; long F1 = 1; long FN; for (long i=1; i<n; i++) { FN = F0 + F1; F0 = F1; F1 = FN; } return FN; } [bvelez@amadeus] ~/icom4015/lec07 >>fibonacci Please enter a positive number (or negative to end): 3 Recursive: F(3) = 2 Iterative: F(3) = 2 Please enter a positive number (or negative to end): 4 Recursive: F(4) = 3 Iterative: F(4) = 3 Please enter a positive number (or negative to end): 8 Recursive: F(8) = 21 Iterative: F(8) = 21 Please enter a positive number (or negative to end): ICOM 4015 - Lecture 2
Example 1Fibonacci Numbers // fibonacci.cc // Iterative and recursive algorithms for computing Fibonacci numbers // Standard C++ header files #include <iostream> // Forward definitions of auxiliary functions long recFibonacci(long n); long iterFibonacci(long n); int main() { long number; while(true) { cout << "Please enter a positive number (or negative to end): "; cin >> number; if (number < 0) return 0; cout << "Recursive: F(" << number << ") = " << recFibonacci(number) << endl; cout << "Iterative: F(" << number << ") = " << iterFibonacci(number) << endl; } } … … ... ICOM 4015 - Lecture 2
Procedural Abstraction IV Iteration vs. RecursionSummary of Concepts • Recursion is as expressive as iteration • Iteration can yield faster code • less duplication of work • less function call overhead • Recursion can yield cleaner code • may rely on a “smart” optimizing compiler to minimize call overhead ICOM 4015 - Lecture 2
Procedural Abstraction V Outline • Further procedural abstraction • Function overloading • Function templates ICOM 4015 - Lecture 2
Function OverloadingSQR Function Family int intSqr (int x) { return x * x } long longSqr(long x) { return x * x; } float floatSqr(float x) { return x * x } Without overloading int sqr (int x) { return x * x } long sqr(long x) { return x * x; } float sqr(float x) { return x * x } With overloading ICOM 4015 - Lecture 2
Function Templates SQR Function Family int sqr (int x) { return x * x } long sqr(long x) { return x * x; } float sqr(float x) { return x * x } With overloading template <class T> T sqr (T x) { return x * x } With templates ICOM 4015 - Lecture 2
SQR’aring different types // Standard C++ header files #include <iostream> #include <iomanip> // Forward definitions of local auxiliary functions template <class T> T sqr(T x); // Main function int main() { cout << " i" << " sqr(i)" << " sqr(float(i))" << " sqr(double(i))" << endl; for (int i=0; i<10; i++) { cout << setw(16) << i << setw(16) << sqr(i) << setw(16) << sqr(float(i)) << setw(16) << sqr(double(i)) << endl; } } // Local auxiliary functions template <class T> T sqr(T x) { return x * x; } Templates can reduce code duplication dramatically ICOM 4015 - Lecture 2
Output [bvelez@amadeus] ~/icom4015/lec09 >>sqr i sqr(i) sqr(float(i)) sqr(double(i)) 0 0 0 0 1 1 1 1 2 4 4 4 3 9 9 9 4 16 16 16 5 25 25 25 6 36 36 36 7 49 49 49 8 64 64 64 9 81 81 81 [bvelez@amadeus] ~/icom4015/lec09 >> ICOM 4015 - Lecture 2
Anatomy of a Function Template T is a type parameter template <class T> function Inside this function T represents any type Templates are C++’s implementation of Parametric Polymorphism ICOM 4015 - Lecture 2
Example 2 // Standard C++ header files #include <iostream> #include <iomanip> // Forward definitions of local auxiliary functions template <class T> void swap(T& a, T& b); template <class T> void doSwap(T a, T b); // Main function int main() { cout << "***** doSwap(1,0)" << endl; doSwap(1,0); cout << endl << endl << "***** doSwap(1.0/3.0, 2.0/3.0)" << endl; doSwap(1.0/3.0, 2.0/3.0); cout << endl << endl << "***** doSwap(true, false)" << endl; doSwap("hello", "world"); } // Local auxiliary functions template <class T> void doSwap(T a, T b) { T x = a; T y = b; cout << "x = " << x << " y = " << y << endl; swap(x,y); cout << "swap(x,y)" << endl; cout << "x = " << x << " y = " << y << endl; swap(x,y); cout << "swap(x,y)" << endl; cout << "x = " << x << " y = " << y << endl; } template <class T> void swap(T& a, T& b) { T temp = a; a = b; b = temp; } Variable declaration of type T ICOM 4015 - Lecture 2
Example 2 Output [bvelez@amadeus] ~/icom4015/lec09 >>swap ***** doSwap(1,0) x = 1 y = 0 swap(x,y) x = 0 y = 1 swap(x,y) x = 1 y = 0 ***** doSwap(1.0/3.0, 2.0/3.0) x = 0.333333 y = 0.666667 swap(x,y) x = 0.666667 y = 0.333333 swap(x,y) x = 0.333333 y = 0.666667 ***** doSwap(true, false) x = hello y = world swap(x,y) x = world y = hello swap(x,y) x = hello y = world ICOM 4015 - Lecture 2
Procedural Abstraction V Function OverloadingSummary of Concepts • Related functions can be grouped under a common name • Overloaded functions may have different return types, but must have different parameters. • The importance of overloading will become clearer when we get into classes and object-oriented programming ICOM 4015 - Lecture 2
Procedural Abstraction V Function TemplatesSummary of Concepts • Programmer declares one function parameterized over some type T • Compiler instantiates potentially many functions for all the different argument types provided among all function calls • Instances must be well typed, that is, all objects should only be used according to their types. ICOM 4015 - Lecture 2