+ All Categories
Home > Documents > Data Structures and Algorithms What is Abstraction?

Data Structures and Algorithms What is Abstraction?

Date post: 01-Jan-2016
Category:
Upload: herbert-norris
View: 223 times
Download: 1 times
Share this document with a friend
Popular Tags:
109
Data Structures and Algorithms What is Abstraction?
Transcript

Data Structures and Algorithms

What is Abstraction?

2

What is abstraction?

• In general terms a computer is nothing but a lot of on/off switches (i.e. 0/1).

• We can manipulate data by changing or evaluating state. We can perform addition, subtraction, and logic analysis.

• We can manipulate where data is stored thru registers and addresses.

3

What is abstraction?

• We make successive abstractions from the state of an on/off value all the way through solving complex problems.

01110100101… 0xeb\0x2a\0x89\0xcd\…. pushl EBP\popl ESI\jmp 0x2a

Binary hex op code (machine instructions) assembly language

int a = 3;\int b = a + 1; x = 3 + 1

High level language real world problem

4

Abstraction

• Every algorithm depends on:– Data: information manipulated by the algorithm– Control flow: order in which instructions are

executed

5

Abstraction in Programming

• Naming -- using descriptive identifiers to denote variables, constants, and complicated data types.

• Top-Down Design -- designing an algorithm by decomposing a problem into subproblems, then decomposing each subproblem, etc.

• Functional Abstraction -- invoking a function to carry out a task without knowing its implementation (mechanism for accomplishing the result).

• Data Abstraction -- separating properties of a data type (its values and operations) from its implementation.

6

Abstraction• Computers execute low level instructions.

– Difficult to understand– Readability is non-existent– Debugging is very difficult– Based on three types of operations

• Unconditional Branch• Conditional Branch• Sub Routine call

• Control structures used in modern languages can implement these in terms of

– if, if – else, if – then – else, and switch operations– do – while, and while operations– functions and procedures

7

Control Abstraction

• Algorithms are divided into two parts– Data Manipulation: How the data is used within the algorithm– Control Flow: The order in which the instructions are executed

• Two forms of control Abstraction– Control Structures: abstraction to low-level machine instructions– Functions & Procedures: abstract multiple actions as single actions.

• The distinction between control and data abstraction is fuzzy. The reason is that data abstractions normally include control abstraction.

8

Control Abstraction

• Control Flow -- the order in which instructions are executed.

• Instructions are normally executed in sequence, one after the other.

• To alter this, high-level languages, like C++ use special instructions called control structures for selection, looping and termination.

Statement Statement Statement . . .

9

Compare

160 IF I >= J GO TO 163161 LET I = I + 3162 GO TO 160163 LET K = 5

500 IF I <= J GO TO 503501 LET A = 20502 GO TO 504503 LET A = 30504 LET B = 2 * a

200 LET I = 0201 LET A = 0202 IF I >= 10 GO TO 205203 LET A = A + 2204 LET I = I + 1205 GO TO 202206 LET B = A

while (i < j) i = i + 3;k = 5;

if (i > j) a = 20;else a = 30;b = 2 * a;

a = 0;for (i = 0;i < 10;i++) a = a + 2;b = a;

10

Control Structures for

• Selection if, if . . else, switch

• Loopingwhile, for, do . . while

• Termination exit( ); causes immediate program terminationreturn; terminates execution of a functionbreak; terminates execution of a loop or switch

11

Choosing Loop Structures• When choosing loops you should not be taken by personal

likes and dislikes• They exist to serve different purposes:

– for loops should be used when the number of interactions is known and constant

– In C++ we have a choice of 2 kinds of indefinite loops•while should be used if the body of the loop may not be executed at all•do – while should be used when the body has to be executed at least

once– for loops in C++ can be used for undefined cases but it may

make your code obscure– break inside loops should avoided. However you may encounter

situations where it does make the code clearer

12

Functional Abstraction

• A powerful mechanism for expressing control abstraction

• A function can be used as a tool for abstraction because its behavior (what it does) can be seperated from its implementation (how it does it).

• Using the technique of functional decomposition a complex problem can be be decomposed into ever smaller subproblems each expressed as a function call.

13

Functions• Software systems can contain millions of

lines of code• A monolithic program would be difficult to

understand, validate, and maintain• Waste resources since no library functions

are used• All major applications organize information

in modular fashion• Functions implement modular design

14

Functions

• Typically perform a specific task

• Can call other functions, themselves

• Similar functions are grouped into libraries

• Standard libraries complement C++1. stdlib, math

Functions must be defined before they are used (called), like variables

Standard library functions are declared in a header file

15

Functional Abstraction

• A function is a named subprogram that performs a specific task when it is called.

• The function’s specification is a description of what the function does.

• Functions use a parameter list for data flow from the caller to the function and from the function to the caller.

1/22/01

Parts of Function Definition

int Cube ( int n ) heading

{ return n * n * n ; body

}

type of value returned

name of function

parameter list

17

Function Definition

• Define function header and function body

• Value-returning functions

return-data-type function-name(parameter list){ constant declarations variable declarations 

other C++ statements 

return value}

18

Function Definition (cont.)

• Non value-returning functions

void function-name(parameter list){ constant declarations variable declarations  other C++ statements}

1/22/01

Parameters classified by location

Always appear in a function call within the calling block.

Always appearin the function heading, or function prototype.

Actual Parameters Formal Parameters

20

• The argument names in the function header are referred to as formal parameters.

int FindMax(int x, int y){ int maximum;  if(x>=y) maximum = x; else maximum = y;  return maximum;}

Function Definition (cont.)

21

Function Prototype

• Every function should have a function prototype. • The function prototype specifies the type of the value that

the function returns (if any) and the type, number, and order of the function's arguments.

return-data-type function-name(argument data types);

or void function-name(argument data types);

22

Function Prototype (cont.)

• The use of function prototypes permits error checking of data types by the compiler.

• It also ensures conversion of all arguments passed to the function to the declared argument data type when the function is called.

1/22/01

A prototype looks like a heading but must end with A prototype looks like a heading but must end with a semicolon; a semicolon; its parameter list just needs the type of each its parameter list just needs the type of each parameter.parameter.

int Cube ( int ) ; // prototype

What is a prototype?

24

Function naming conventions used

• Names of value-returning functions should be nouns (things) or phrases that describe the kind of value (or condition) returned.

if (IsSeniorCitizen(thisAge))discountRate = 0.15;

squareFeet = Area(length, width);

• Names of non-value-returning functions should be command verbs.

PrintHeading(numStars);

25

Calling a function

• A function is called by specifying its name followed by its arguments.

• Non-value returning functions: function-name (data passed to function);

• Value returning functions: results = function-name (data passed to function);

26

Calling a function (cont.)

#include <iostream.h> int FindMax(int, int); // function prototype int main(){ int firstnum, secnum, max;  cout << "\nEnter two numbers: "; cin >> firstnum >> secnum;  max=FindMax(firstnum, secnum); // the function is called here  cout << "The maximum is " << max << endl;  return 0;}

• The argument names in the function call are referred to as actual parameters

27

Calling a function by value

• The function receives a copy of the actual parameter values.

• The function cannot change the values of the actual parameters.

28

Calling a function by reference

• Very useful when we need a function which "returns more than one value".

• The formal parameter becomes an alias for the actual parameter.

• The function can change the values of the actual parameters.

29

#include <iostream.h> 

void newval(float&, float&); // function prototype 

int main(){ float firstnum, secnum;  cout << "Enter two numbers: "; cin >> firstnum >> secnum;  newval(firstnum, secnum);  cout << firstnum << secnum << endl;  return 0;} void newval(float& xnum, float& ynum){ xnum = 89.5; ynum = 99.5;}

Calling a function by reference (cont.)

30

The "const" modifier

• Call by reference is the preferred way to pass a large structure or class instances to functions, since the entire structure need not be copied each time it is used!!

• C++ provides us with protection against accidentally changing the values of variables passed by reference with the const operator

function prototype: int FindMax(const int&, const int&);

function header: int FindMax(const int& x, const int& y);

31

Parameters

• Default Behavior of simple types like int, char, float, double are always value parameters, unless you do something to change that.

• To get a reference parameter you need to place & after the type in the function heading and prototype.

1/22/01

When to use reference parameters?

• Reference parameters should be used when you want your function to give a value to, or change the value of, a variable from the calling block without an assignment statement in the calling block.

1/22/01

CALLING BLOCK MEMORY

25

4000

Age

If you pass only a copy of 25 to a function, it is called “pass-by-value” and the function will not be able to change the contents of Age. It is still 25 when you return.

1/22/01

CALLING BLOCK MEMORY

25

4000

Age

BUT, if you pass 4000, the address of BUT, if you pass 4000, the address of Age to a function, it is called Age to a function, it is called “pass-by-“pass-by-reference”reference” and the function will be able and the function will be able to change the contents of Age. It could to change the contents of Age. It could be 23 or 90 when you return.be 23 or 90 when you return.

1/22/01

Value Parameter Reference Parameter

The value (25) of theactual parameter is passed to the function when it is called.

The memory address (4000)of the actual parameter is passed to the function when it is called.

25

4000

Age

CALLING BLOCK MEMORYCALLING BLOCK MEMORY

1/22/01

Pass-by-reference is also called . . .

• Pass-by-address, or

• Pass-by-location.

1/22/01

Pass-by-value

CALLINGBLOCK

FUNCTION CALLED

“incoming”

value ofactual parameter

1/22/01

Pass-by-reference

CALLINGBLOCK FUNCTION

CALLED

actual parameter has no value yet when call occurs

“outgoing”

new value ofactual parameter

1/22/01

Pass-by-reference

CALLINGBLOCK FUNCTION

CALLED

“incoming”

original value ofactual parameter

“outgoing”

changed value ofactual parameter

1/22/01

Parameters classified by purpose

/* in */ one-way flow of data into the function

/* out */ one-way flow of data out of the function

/* inout */ two-way flow into and out of the function

Parameter Data Flow

1/22/01

For all data types EXCEPT arrays--

/* in */ value

/* out */ reference & after the type

/* inout */ reference & after the type

Data Flow Pass by Formal Parameter Needs

1/22/01

For arrays--

/* in */ reference const before the type

/* out */ reference

/* inout */ reference

Data Flow Pass by Formal Parameter Uses

43

Abstraction Techniques

• Functional Abstraction

• Top-down design

• Data Abstraction (Central Theme of this course)

44

Functional Decomposition

• Probably the most powerful abstraction mechanism• A large task is decomposed (divided) into smaller

(complete) tasks which are implemented as functions (or methods)

• The programmer can than use these functions, make assumptions about their behaviour without worrying about implementation details

– Increases software reuse– Improves software reliability as components can be tested

independently and thoroughly• The function specification is what the programmer needs to

know

45

Functional Decomposition

• Functions can return value or not (sometimes called procedures)

• When designing functions we have to pay attention to data flow

– One way flow into the function– One way flow out of the function– Two way flow into and out of the function

46

Flow into the Function

• The caller passes some data to the function but does not expect the function to modify the actual data.

• In this case parameters should be passed by value // exp must be a positive number

int power(int base, int exp) { int power = 1; for (int i=0; i<exp; i++) { power = power * base; } return power}

// exp must be a positive numberint power(int base, int exp) { int power = 1; for (int i=0; i<exp; i++) { power = power * base; } return power}

47

Flow out of the Function

• The caller passes the location of the data as parameter (pass by reference)

• The functions modifies the value stored in the location without considering the value currently stored

// initialize variablesvoid initialize(float& a, float& b) { a = 1000; b = 100;}

// initialize variablesvoid initialize(float& a, float& b) { a = 1000; b = 100;}

48

Two-way flow into and from the Function

• The caller is passing the location of the date (address) as a parameter (pass by reference)

• The function inspect the value currently stored in the location and will possibly modify it.

// initialize variablesvoid update(float& a, float& b) { a = a + 1000; b = b + 100;}

// initialize variablesvoid update(float& a, float& b) { a = a + 1000; b = b + 100;}

49

Software Design: Standard Functions

Problem Specification:

Write a program to compute the real roots of a quadratic equation

Problem Analysis:We need the three coefficients of a quadratic equationUsing these coefficients we need to determine if the roots will be real or notDetermine the value of the roots

02 cbxaxRecall:

50

Software Design: Standard Functions

Data Requirements:Problem Input

a (double) - square term coefficientb (double) - linear term coefficientc (double) - constant term

Problem Outputequation and roots if realequation and message otherwise

acabb

*2**42 Recall, the roots of a quadratic

equation are given as:

51

Software Design: Standard Functions

Problem Analysis, cont:

Additional Program Variables

radical (double) - cab **42

root_one (double) - a

cabb

*2

**42

root_two (double) - a

cabb

*2

**42

52

Software Design: Standard Functions

Program Design:

Initial Design:1) Read square, linear, and constant terms2) Display message if imaginary roots3) Compute roots4) Display real roots

Step 2 refinement:2.1) inside radical is less than or equal to zero2.2) square coefficient (a) is zero

53

Software Design: Standard Functions

Program Implementation:// FILE: quadratic.cc// Program computes the real root of the specified quadratic equation

#include <stdlib >#include <iostream>#include <math>

using namespace std;

int main () {

// Read square, linear, and constant coefficients cout << “Coefficients of the quadratic equation: “; double a, b, c; cin >> a >> b >> c;

// Determine if imaginary roots if ((a == 0.0) || ((b * b – 4 * a * c) < 0 ) { cout << a << “ x**2 + “ << b << “ x + “ << c << “ does NOT have real roots” << endl; } else { double radical = sqrt (b * b – 4 * a * c); double root_one = (-b + radical) / (2 * a); double root_one = (-b - radical) / (2 * a); cout << “The roots of “ << a << “ x**2 + “ << b << “ x + “ << c << “ are “ << root_one << “ and “ << root_two << endl; } // end if()-else() return 0;} // end main()

54

Functions• The math function sqrt takes one argument and

returns a double• function call: flow of control transferred to the

function• function interface or signature, must be specified

before function is used

1) return type2) function name3) parameter descriptions

55

Functions

• Function prototypes are the same as the function signature with a trailing semi-colon

• double cos(double x);

• double my_function(int count, int object);

56

Functions

• Function so far have passed a single parameter and returned the desired value.

• What if we want to return 2 or more values?• Modify the value of a function argument?• Not the way we have passed parameters!

Pass by value: copy of the value is made!

We want to pass a reference to the parameter.

A reference is essentially the memory address of the parameter

57

Functions

Problem Specification:

Rewrite the quadratic program so that the roots are determined and returned in a function.

Problem Analysis:Similar to before

1/22/01

Example of Pass-by-Reference

• We want to find 2 real roots for a quadratic equation ax2 + bx + c = 0 with coefficients a, b, and c.

• Write a prototype for a void function named GetRoots( ) with 5 parameters. The first 3 parameters are type float. The last 2 are reference parameters of type float.

1/22/01

void GetRoots ( float , float , float , float& , float& );

• This function will use 3 incoming values a, b, c from the calling block.

• It will calculate 2 outgoing values Root1 and Root2 for the calling block.

• They are the 2 real roots of the quadratic equation with coefficients a, b, c.

// prototype// prototype

60

GetRoots()

void GetRoots( float a, float b, float c, float& Root1,void GetRoots( float a, float b, float c, float& Root1, float& Root2 ) float& Root2 ){{ float temp; float temp;

temp = b * b - 4.0 * a * c; temp = b * b - 4.0 * a * c;

Root1 = (-b + sqrt(temp) ) / ( 2.0 * a ); Root1 = (-b + sqrt(temp) ) / ( 2.0 * a );

Root2 = (-b - sqrt(temp) ) / ( 2.0 * a ); Root2 = (-b - sqrt(temp) ) / ( 2.0 * a );

return; return;}}

#include <iostream.h>#include <fstream.h>#include <math.h>void GetRoots(float, float, float, float&, float&);int main ( ) { ifstream infile( "in_file"); ofstream outfile( "out_file"); float a, b, c, First, Second; int count = 0; if ( ! infile ) {

cerr<<"eror: unable to open input file!\n"; return -1;

} if ( ! outfile ) {

cerr<<"error: unable to open output file!\n"; return -2;

} while ( infile ){ infile >> a >> b >> c; GetRoots(a, b, c, First, Second); //call outfile << a<<endl << b<<endl << c<<endl << First<<endl <<

Second<<endl; }}

62

Iostream manipulators

setw (int w) - set widthsetprecision(int d) - number of places is dios::fixed - use decimal notation for floating-pointsetf(ios::fixed) - sets decimal notationsetfill(‘a’) - sets the fill character

63

Iostream manipulators

• cout is the standard output object

• cin is the standard input object

• methods or member functions: functions associated with objects

• cout and cin have associated functions

• input and output stream manipulators endl is an ostream manipulator

iomanipulator functions are defined in the header file: iomanip

64

Table of Function Values

Problem Specification:Write a program to list the values of various math functions in tabular form.

Problem Analysis:Use log, log10, and sqrt math functionsTable format: x log(x) log10(x) sqrt(x)

Use a column format

Use values of x as: 1->10, 20 ->100, 1000 ->100000

65

Table of Function Values

// FILE: values.cc// Program prints a formatted table of some standard mathematical function

#include <iostream>#include <iomanip>#include <cmath>using namespace std;

int main () { const int colWidth = 9; double x = 1.0;

cout << setw(colWidth) << “x“<< setw(colWidth) << “ln” << setw(colWidth) << “log” << setw(colWidth) << “sqrt” << endl; cout << setfill(‘=’) << setw(4 * colWidth) << “=” << endl; cout << setfill(‘ ‘); cout.setf(ios::fixed);

while (x < 1000000) { cout << setpercision(0) << setw(colWidth) << x << setpercision(4) << setw(colWidth) << log(x) << setw(colWidth) << log10(x) << setw(colWidth) << sqrt(x) << endl; if (x < 10) { x++; } else if (x < 100) { x += 10; } else { x *= 10; } } // end while(x < 10000000) return 0;} // end main()

66

Table of Function Values

• include header filesiostream: cin and cout

include namespace std

Eliminates std::cin and std::cout

ios::fixed is an enumerated type

:: the scope operator, tells which class the value comes from

iomanip: setw(), setfill(), setf() setprecision()cmath: log(), log10(), sqrt()

67

Table of Function Values

• while loop: control structureMake sure each pass gets closer to loop termination => infinite loopif(): control structure

if(){} else if() {}: control structure

x++, ++x: post and pre increment operators

x += 10 : compound assignment operator

x--, --x: post and pre decrement operators

x += 10 same as x = x + 10;

68

Table of Function Values

x ln log sqrt

====================================

1 0.0000 0.0000 1.0000 2 0.6931 0.3010 1.4142 3 1.0986 0.4771 1.7321 4 1.3863 0.6021 2.0000 5 1.6094 0.6990 2.2361 6 1.7918 0.7782 2.4495 7 1.9459 0.8451 2.6458 8 2.0794 0.9031 2.8284 9 2.1972 0.9542 3.0000 10 2.3026 1.0000 3.1623 20 2.9957 1.3010 4.4721 30 3.4012 1.4771 5.4772 40 3.6889 1.6021 6.3246 50 3.9120 1.6990 7.0711 60 4.0943 1.7782 7.7460 70 4.2485 1.8451 8.3666 80 4.3820 1.9031 8.9443 90 4.4998 1.9542 9.4868 100 4.6052 2.0000 10.0000 1000 6.9078 3.0000 31.6228 10000 9.2103 4.0000 100.0000 100000 11.5129 5.0000 316.2278

Program output:

69

Top-Down Approach

• Programming consists of designing solutions to real world problems that can be applied to machines Specify the

ProblemSpecify the

Problem

Design Top-LevelAlgorithm

Design Top-LevelAlgorithm

Refine algorithmsinto subalgorithmsRefine algorithmsinto subalgorithms

refine subalgorithmsfurther

refine subalgorithmsfurther

translate refined algorithmsinto program

translate refined algorithmsinto program

70

Roman Numeral Evaluator Specification

• Description: The program should accept a simple expression using roman numerals and give the result of the expression in decimals.

• Input: Each line consists of two roman numerals and a operator. Roman numerals should be in upper case and operator should be (+, -, * or /)

• Output: The result of the operation in decimals• Error Handling: If input is not correct the output

should be "Bad Data"

71

Roman Numeral Evaluator Stepwise Refinement

For each input line Convert roman numbers to decimal If operation is valid Print result of operation else Print error message

For each input line Convert roman numbers to decimal If operation is valid Print result of operation else Print error message

72

Roman Numeral Evaluator Stepwise Refinement

Prompt for input of roman number 1While not end-of-file signal Prompt operator and roman number 2 Convert roman numbers to decimal If operation is valid Print result of operation else Print error message Prompt for input of roman number 1

Prompt for input of roman number 1While not end-of-file signal Prompt operator and roman number 2 Convert roman numbers to decimal If operation is valid Print result of operation else Print error message Prompt for input of roman number 1

73

Roman Numeral Evaluator Stepwise Refinement

Prompt for input of roman1While not end-of-file signal Prompt operator and roman2 decimal1 = convert roman1 to decimal decimal2 = convert roman2 to decimal If operation is valid Apply operation to decimal1 and decimal2 Print result of operation else Print error message Prompt for input of roman1

Prompt for input of roman1While not end-of-file signal Prompt operator and roman2 decimal1 = convert roman1 to decimal decimal2 = convert roman2 to decimal If operation is valid Apply operation to decimal1 and decimal2 Print result of operation else Print error message Prompt for input of roman1

74

Roman Numeral EvaluatorStepwise Refinement

#include <iostream.h>

typedef int Boolean;const int TRUE = 1;const int FALSE = 0;

// Function stubsvoid printValue(int,char,int);void convert(const char[], int&, Boolean&);

int main() { char str1[31]; char str2[31]; char op; int dec1; int dec2; Boolean str1Valid; Boolean str2Valid; Boolean opValid;

#include <iostream.h>

typedef int Boolean;const int TRUE = 1;const int FALSE = 0;

// Function stubsvoid printValue(int,char,int);void convert(const char[], int&, Boolean&);

int main() { char str1[31]; char str2[31]; char op; int dec1; int dec2; Boolean str1Valid; Boolean str2Valid; Boolean opValid;

75

Roman Numeral EvaluatorStepwise Refinement

cout << "Roman numeral expression:\n"; while (cin >> str1) { cin >> op >> str2; convert(str1,dec1,str1Valid); convert(str2,dec2,str2Valid); opValid = (op=='+' || op=='-' || op=='*' || op=='/'); if (str1Valid && str2Valid && opValid) printValue(dec1,op,dec2); else cout << "Bad Data!"; cout << "Roman numeral expression:\n"; } return 0;}

cout << "Roman numeral expression:\n"; while (cin >> str1) { cin >> op >> str2; convert(str1,dec1,str1Valid); convert(str2,dec2,str2Valid); opValid = (op=='+' || op=='-' || op=='*' || op=='/'); if (str1Valid && str2Valid && opValid) printValue(dec1,op,dec2); else cout << "Bad Data!"; cout << "Roman numeral expression:\n"; } return 0;}

76

Roman Numeral EvaluatorWhat else?

• Draw hierarchy charts• Do further refinement

– Stubs should be implemented• Perhaps even using further stubs!

– Functions can be further divided– Functions could be implemented to be more

generic

• Update hierarchy charts

1/22/01

Top-down Testing with Function Stubs

• A function stub is an unrefined function definition (with formal parameters but incomplete body) that enables you to run your program to determine if your algorithm logic is correct in the caller.

• The function stub body generally contains cout << “function Whatname entered”;

and any /*out*/ parameter is assigned an arbitrary value.

1/22/01

Bottom-up Testing

• Test driver is a separate main function written just to call a new function which it will test using a test oracle (of possible input data and predicted outputs), so you can determine whether the new function meets specifications.

79

Bottom-up Testing

• As important as Top-Down Testing• Instead of using stubs a "main" program is written to

test the logic of the functions. This function is normally called a Test Driver

• A good way to write algorithms is combining top-down with bottom-up development/testing

– It increases productivity– A groups of programs can test the higher level logic while

another group can code and test the lower level routines• The combination of both normally shorten the project

time

80

Roman Numeral Evaluator Bottom-Up testing

#include <iostream.h>

typedef int Boolean;const int TRUE = 1;const int FALSE = 0;

int main() { char str[31]; int decVal; Boolean strValid; while (cin >> str) { convert(str,decVal,strValid); if (strValid) cout << "VALID"; else cout << "NOT VALID"; } return 0;}

#include <iostream.h>

typedef int Boolean;const int TRUE = 1;const int FALSE = 0;

int main() { char str[31]; int decVal; Boolean strValid; while (cin >> str) { convert(str,decVal,strValid); if (strValid) cout << "VALID"; else cout << "NOT VALID"; } return 0;}

81

Documentation

• On any process of developing algorithms it is very important to document your code

• Internal documentation is as important as design documentation.

– It is used when the program need to be changed• The most commonly used internal program

documentation is:– Assertions– Loop Invariants– Pre Conditions– Post Conditions

1/22/01

An Assertion

• Is a programmer’s claim (with a value of true or false) about the contents of program variables at a particular location in program execution and is written as a comment (using English and symbols, not necessarily in C++ code).

83

Assertions

• Becoming widely accepted as documentation• Shows the state of computation in a given point in the code• It is like a snapshot of the internal state of the program`• Should be written as a fact (something that the programmer

believes to be true)• An assertion has a value true of false therefore should be

written as a logical statement• Can be used to prove the correctness• Should be placed correctly in the program and written using

language-independent statements

84

Some Assertions

// ASSERT: 1 <= month <= 13

// ASSERT: all previous values of age were <= 0

// ASSERT: total == 1 + 2 + . . . + (count -1)

// ASSERT: sum >= 0 && count > 0

// ASSERT: 0.0 <= deptSales <= 25000.0

85

Examples: Assertions

for (i = 0; i < 50; i++) myArray[i] = 0;// ASSERT: All myArray[0..49] == 0

for (i = 0; i < 50; i++) myArray[i] = 0;// ASSERT: All myArray[0..49] == 0

if (a < b) max = b;else max = a;// ASSERT: max has the maximum value between (a,b)

if (a < b) max = b;else max = a;// ASSERT: max has the maximum value between (a,b)

86

Pre and Post-Conditions

• Used to document functions• Defines the function behavior

– Pre-conditions define what the function require to be "true" at the time it is called.

– Post-condition define the state of computation at the time the function finishes its execution

• The pre and post conditions are related. If the pre-condition is guaranteed the post-condition will happen.

• The caller should ensure the pre-condition and the function code the post-condition

1/22/01

Preconditions and Postconditions

• The precondition describes every condition of formal parameters that the function requires at the moment the function is invoked.

• The postcondition describes the condition, particularly for reference parameters, when the function finishes execution.

void GetRoots( /* in */ float a, /* in */ float b,

/* in */ float c, /*out */ float& Root1,

/* out */ float& Root2 )

// PRE: Assigned(a) && Assigned(b) && Assigned(c)

// && a != 0 && b*b - 4*a*c >= 0

// POST: Root1 and Root2 are roots of quadratic with

// coefficients a, b, c

{ float temp;

temp = b * b - 4.0 * a * c;

Root1 = ( -b + sqrt ( temp ) ) / ( 2.0 * a ) ;

Root2 = ( -b - sqrt ( temp ) ) / ( 2.0 * a ) ;

return;

}

int strLength ( /* in */ const char str [ ] )

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

// PRE: str is a null- terminated string

// POST: FCTVAL == length of str (not counting ‘\0’ )

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

{ int i = 0 ;

while ( str [ i ] != ‘\0’ )

i ++;

return i ;

}

90

Example: Pre/Post Conditions

// PRE: assigned(ch1) && assigned(ch2)// POST: the values of ch1 and ch2 have been interchanged void swapChars (/* INOUT */ char& ch1, /* INOUT */ char& ch2) { char auxChar = ch1; ch1 = ch2; ch2 = auxChar;}

// PRE: assigned(ch1) && assigned(ch2)// POST: the values of ch1 and ch2 have been interchanged void swapChars (/* INOUT */ char& ch1, /* INOUT */ char& ch2) { char auxChar = ch1; ch1 = ch2; ch2 = auxChar;}

// PRE: assigned(aNumber) && aNumber >= 1// POST: FCTVAL == aNumber * (aNumber-1) * (aNumber-2) * ... * 1int factorial (/* IN */ int aNumber) { if (aNumber == 1) return 1; else return (aNumber * factorial(anumber - 1));}

// PRE: assigned(aNumber) && aNumber >= 1// POST: FCTVAL == aNumber * (aNumber-1) * (aNumber-2) * ... * 1int factorial (/* IN */ int aNumber) { if (aNumber == 1) return 1; else return (aNumber * factorial(anumber - 1));}

91

Loop Invariants

• Its is a special kind of assertion but got its own name!

• A loop invariant is an assertion that is placed inside the loop and must be true every time the loop reaches it. Therefore it must be true:

– Initially, after any interaction steps but before the loop begins

– Before every iteration of the loop– After every iteration of the loop– After the loop terminates

1/22/01

While Loop Invariant

• The while loop invariant is true just before loop entry, just after the loop body has executed for the last time, and after every loop iteration in between.

• It is not necessarily true at each point inside the loop body.

1/22/01

Examples of Loop Invariants

while loop condition related Invariant

count = 0;

while (count < 100) 0 <= count <= 100

count = 4;

while (count > 0) 0 <= count <= 4

94

Where to place the loop invariant?

• The most useful location is immediately BEFORE the loop test.

• With a for or while loop, physically place the invariant at the top of the loop body, with the remark “prior to test” to indicate that the invariant is logically located BEFORE the loop test.

• With a do-while loop, place the loop invariant at the bottom of the loop body, immediately before the test.

95

While Loop Invariant

sum = 0 ;

count = 1 ;

while ( count <= 10 ) {

// INV (prior to test) :

// sum == 1 + 2 + . . . + count-1 // && 1 <= count <= 11

sum = sum + count ;

count++ ;

}

96

For Loop Invariant

sum = 0 ;

for ( count = 1 ; count <= 10 ; count++ ) {

// INV (after initialization,

// but prior to test) :

// sum == 1 + 2 + . . . + count-1 // && 1 <= count <= 11

sum = sum + count ;

}

97

Do-While Loop Invariant

sum = 0 ;

count = 1 ;

do {

sum = sum + count ;

count++ ;

// INV:

// sum == 1 + 2 + . . . + count-1 // && 2 <= count <= 11

} while ( count <= 10 ) ;

98

Case Study Sorting an Array

• Problem description– Input a collection of up to 100 integers from the

keyboard, sort them into ascending order and print the sorted collection

– If there are fewer than 100 numbers the user should use end-of-file keystroke (Ctrl-D?)

• By using arrays we can use algorithms that consider the size of the arrays in their logic and need to manipulate the arrays indexes.

• We will use selection sort

99

Sorting an Array-1st Step

• Postpone details until later• Debug the code at each level of the stepwise refinement• Let us use top down testing using C++

1. Prompt user to enter the values2. Store the data into the array3. Sort the array4. Display sorted array

1. Prompt user to enter the values2. Store the data into the array3. Sort the array4. Display sorted array

100

Sorting an Array-2nd Step

#include <iostream.h>

const int MAX_SIZE = 100;

// Functions prototypes (allow the use of stubs)void inputValues (int[],int&);void sort (int[],int);void outputValues(const int[], int);

int main() { int theArray[100]; int size; inputValues(theArray,size); sort(theArray,size); // ASSERT: theArray[0..size-1] is in ascending order outputValues(theArray,size); return 0;}

#include <iostream.h>

const int MAX_SIZE = 100;

// Functions prototypes (allow the use of stubs)void inputValues (int[],int&);void sort (int[],int);void outputValues(const int[], int);

int main() { int theArray[100]; int size; inputValues(theArray,size); sort(theArray,size); // ASSERT: theArray[0..size-1] is in ascending order outputValues(theArray,size); return 0;}

101

Sorting an Array-3rd Step

// POST: size == number of input values // && size <= MAX_SIZE// && theArray[0..size-1] contains the input valuesvoid inputValues( /* OUT */ int theArray[], /* IN */ int& size) { cout << "INPUT FUNCTION\n"; size = 3; theArray[0] = 13; theArray[1] = 2; theArray[2] = 55;}

// POST: size == number of input values // && size <= MAX_SIZE// && theArray[0..size-1] contains the input valuesvoid inputValues( /* OUT */ int theArray[], /* IN */ int& size) { cout << "INPUT FUNCTION\n"; size = 3; theArray[0] = 13; theArray[1] = 2; theArray[2] = 55;}

102

Sorting an Array 3rd Step

// PRE: assigned(size) && assigned(theArray[0..size-1]// POST: values of theArray[0..size-1] are rearranged in ascending// ordervoid sort( /* INOUT */ int theArray[], /* IN */ int size) { cout << "SORT FUNCTION\n"; theArray[0] = 2; theArray[1] = 13; theArray[2] = 55;}

// PRE: assigned(size) && assigned(theArray[0..size-1]// POST: values of theArray[0..size-1] are rearranged in ascending// ordervoid sort( /* INOUT */ int theArray[], /* IN */ int size) { cout << "SORT FUNCTION\n"; theArray[0] = 2; theArray[1] = 13; theArray[2] = 55;}

103

Sorting an Array-3rd Step

// PRE: assigned(size) && assigned(theArray[0..size-1]// POST: values of theArray[0..size-1] are displayedvoid outputValues(/* IN */ const int theArray[], /* IN */ int size) { cout << "OUTPUT FUNCTION\n"; cout << theArray[0] << '\n'; cout << theArray[1] << '\n'; cout << theArray[2] << '\n';}

// PRE: assigned(size) && assigned(theArray[0..size-1]// POST: values of theArray[0..size-1] are displayedvoid outputValues(/* IN */ const int theArray[], /* IN */ int size) { cout << "OUTPUT FUNCTION\n"; cout << theArray[0] << '\n'; cout << theArray[1] << '\n'; cout << theArray[2] << '\n';}

104

Sorting an Array-4th Step

// POST: size == number of input values // && size < 100// && theArray[0..size-1] contains the input valuesvoid inputValues( /* OUT */ int theArray[], /* IN */ int& size) { cout << "INPUT FUNCTION\n"; size = 0; while (size < MAX_SIZE && cin >> theArray[size]) // INV: theArray[0..size-1 have been input & size <= MAX_SIZE size++;}

// POST: size == number of input values // && size < 100// && theArray[0..size-1] contains the input valuesvoid inputValues( /* OUT */ int theArray[], /* IN */ int& size) { cout << "INPUT FUNCTION\n"; size = 0; while (size < MAX_SIZE && cin >> theArray[size]) // INV: theArray[0..size-1 have been input & size <= MAX_SIZE size++;}

105

Sorting an Array-4th Step

// PRE: assigned(size) && assigned(theArray[0..size-1]// POST: values of theArray[0..size-1] are displayedvoid outputValues( /* IN */ const int theArray[], /* IN */ int size) { cout << "OUTPUT FUNCTION\n"; for (int i = 0; i < size; i++) // INV: theArray[0..i-1] have been output && i <= size cout << theArray[i] << '\n';}

// PRE: assigned(size) && assigned(theArray[0..size-1]// POST: values of theArray[0..size-1] are displayedvoid outputValues( /* IN */ const int theArray[], /* IN */ int size) { cout << "OUTPUT FUNCTION\n"; for (int i = 0; i < size; i++) // INV: theArray[0..i-1] have been output && i <= size cout << theArray[i] << '\n';}

106

Sorting an Array-Selection Sort

45 23 12 5 27 8

Bottom

8 23 12 5 27 45

Bottom

8 23 12 5 27 45

Bottom

8 5 12 23 27 45

Bottom

8 5 12 23 27 45

Bottom

5 8 12 23 27 45

Bottom

107

Sorting an Array-4th Step

// PRE: assigned(size) && assigned(theArray[0..size-1]// POST: values of theArray[0..size-1] are rearranged in ascending// ordervoid sort( /* INOUT */ int theArray[], /* IN */ int size) { for (int bottom = size-1; bottom >=1; bottom--) { FIND THE INDEX OF LARGEST (indexLarge) NUMBER IN theArray if (indexLarge != bottom) SWAP theArray[indexLarge] and theArray[bottom] }}

// PRE: assigned(size) && assigned(theArray[0..size-1]// POST: values of theArray[0..size-1] are rearranged in ascending// ordervoid sort( /* INOUT */ int theArray[], /* IN */ int size) { for (int bottom = size-1; bottom >=1; bottom--) { FIND THE INDEX OF LARGEST (indexLarge) NUMBER IN theArray if (indexLarge != bottom) SWAP theArray[indexLarge] and theArray[bottom] }}

108

Sorting an Array-5th Step

// PRE: assigned(size) && assigned(theArray[0..size-1]// POST: values of theArray[0..size-1] are rearranged in ascending// ordervoid sort( /* INOUT */ int theArray[], /* IN */ int size) { int indexLarge; for (int bottom = size-1; bottom >=1; bottom--) { // INV: All elements in theArray[0..bottom] <= theArray[bottom+1] // && theArray[bottom+1..size-1] are ordered // && bottom >= 0 indexLarge = 0; for (int i=1; i<=bottom;i++) // INV: theArray[indexLarge] >= all elements in theArray[0..i-1] // && i <= bottom+1 if (theArray[i] > theArray[indexLarge]) indexLarge = i; if (indexLarge != bottom) swap(theArray[indexLarge],theArray[bottom]); }}

// PRE: assigned(size) && assigned(theArray[0..size-1]// POST: values of theArray[0..size-1] are rearranged in ascending// ordervoid sort( /* INOUT */ int theArray[], /* IN */ int size) { int indexLarge; for (int bottom = size-1; bottom >=1; bottom--) { // INV: All elements in theArray[0..bottom] <= theArray[bottom+1] // && theArray[bottom+1..size-1] are ordered // && bottom >= 0 indexLarge = 0; for (int i=1; i<=bottom;i++) // INV: theArray[indexLarge] >= all elements in theArray[0..i-1] // && i <= bottom+1 if (theArray[i] > theArray[indexLarge]) indexLarge = i; if (indexLarge != bottom) swap(theArray[indexLarge],theArray[bottom]); }}

109

Sorting an Array-6th Step

// PRE: assigned(val1) && assigned(val2)// POST: values of val1 and val2 have been interchangedvoid swap( /* INOUT */ int& val1, /* INOUT */ int& val2) { int temp = val1; val1 = val2; val2 = temp;}

// PRE: assigned(val1) && assigned(val2)// POST: values of val1 and val2 have been interchangedvoid swap( /* INOUT */ int& val1, /* INOUT */ int& val2) { int temp = val1; val1 = val2; val2 = temp;}


Recommended