300 likes | 427 Views
Dr Deepak B Phatak Subrao Nilekani Chair Professor Department of CSE, Kanwal Rekhi Building IIT Bombay Lecture 7, Efficiency of programs Thursday 1 July 2010. Two-week ISTE workshop on Effective teaching/learning of computer programming. Overview. Efficiency of programs
E N D
Dr Deepak B Phatak Subrao Nilekani Chair Professor Department of CSE, Kanwal Rekhi Building IIT Bombay Lecture 7, Efficiency of programs Thursday 1 July 2010 Two-week ISTE workshop onEffective teaching/learning of computer programming
Overview • Efficiency of programs • Notion of time complexity • Example • Estimating value of PI • Calculating terms of Fibonacci series [Some slides courtesy Prof Milind Sohoni]
Computational time • Although the computer works very fast, it does take a finite amount of time for every computation • If we do not carefully design our program, we may force the machine to do many more computations than necessary to solve the problem • The order of magnitude of time required to execute any program is called its “Time Complexity” • We should design our algorithm (steps in our program) such that the execution time is minimized
Estimating value of PI #include <iostream> using namespace std; // estimate pi int main(){ float pi; int i, j, N, count; cout << “Give value of N\n”; cin >> N;
Estimating PI … count=0; for (i=1;i<=N;i=i+1){ for (j=1;j<=N;j=j+1){ if (i*i+j*j<=N*N) count=count+1; }; }; pi=4.0*count/(N*N); cout << pi << “\n”; return 0; }
Estimating PI … count=0; for (i=1;i<=N;i=i+1){ for (j=1;j<=N;j=j+1){ if (i*i+j*j<=N*N) count=count+1; }; }; pi=4.0*count/(N*N); cout << pi << “\n”; return 0; }
Quiz Q. We have declared our variables i, j, N as integers, the effect on the estimation of Pi using pi=4.0*count/(N*N); will be • Negligible, we have declared pi as float • Very large, because the division operation in the final formula [count/(N*N)] is of the type integer divided by integer • Very large because the values of some terms may be beyond the limits of integer representation • None of these
Modified program version 1 #include <iostream> using namespace std; // estimate pi int main() { float pi; float i,j,N; long count; cout << "N? " ; cin >> N;
Modified program version 1 … count=0; for (i=1;i<=N;i=i+1){ for (j=1;j<=N;j=j+1){ if (i*i+j*j<=N*N) count=count+1; }; }; pi=4.0*count/(N*N); cout << "Value of Pi is: " << pi << "\n"; return 0; }
Execution results [dbp@localhost cpp]$ c++ calculatepi.cpp -o pi [dbp@localhost cpp]$ ./pi N? 1000 Value of Pi is: 3.13755 [dbp@localhost cpp]$ ./pi N? 10000 Value of Pi is: 3.14119
Determining computational efficiency • Having ensured that our program works correctly, we now wish to determine how long it takes to run the program for different values of N • we want to find the execution time using some utility program which internally keeps time while the Operating System (OS) runs our program • UNIX OS and its variants provide a utility program called ‘time’ • ALL OS’s provide such utilities • Special software used for simulating large number of concurrent users • Loadrunner, J-meter, ...
Measuring execution time • We can use this command to run our program under its control [dbp@localhost cpp]$ time ./pi N? 10000 Value of Pi is: 3.14119 real 0m3.690s user 0m1.076s sys 0m0.012s • What do these different values signify?
Explanations • Real time means the total clock time which the program took to execute from start to finish • Includes time spent by us in giving input values • user time and sys (system) time are two independent time counts • User time is actually the computing time taken by the computer to execute the program • Sys time is the time which was spent by the supervising OS for executing our program • User time represents our algorithmic time complexity
Execution results [dbp@localhost cpp]$ c++ calculatepi.cpp -o pi [dbp@localhost cpp]$ time ./pi N? 1000 Value of Pi is: 3.13755 real 0m2.496s user 0m0.000s sys 0m0.000s [dbp@localhost cpp]$ time ./pi N? 10000 Value of Pi is: 3.14119 real 0m3.690s user 0m1.076s sys 0m0.012s
Execution results … [dbp@localhost cpp]$ time ./pi N? 20000 Value of Pi is: 3.14139 real 0m7.181s user 0m4.304s sys 0m0.000s [dbp@localhost cpp]$ time ./pi N? 50000 Value of Pi is: 3.14151 real 0m29.742s user 0m26.714s sys 0m0.000s [dbp@localhost cpp]$
Further reduction in execution time • We observe that the major computation is happening during evaluation of if condition • if (i*i+j*j<=N*N) count=count+1 • This computation is done within a nested iteration each running N times. (so N2 times) • We notice that while the values of i and j are changing every time, that of N is fixed during all iterations • So why calculate N*N again and again?
Modified program version 2 … int n2 = N*N; count=0; for (i=1;i<=N;i=i+1){ for (j=1;j<=N;j=j+1){ if (i*i+j*j<=n2) count=count+1; }; }; pi=4.0*count/n2;
Execution results … [dbp@localhost cpp]$ c++ calculatepiv2.cpp -o v2 [dbp@localhost cpp]$ time ./v2 N? 20000 Value of Pi is: 3.14139 real 0m7.821s user 0m4.308s sys 0m0.012s [dbp@localhost cpp]$ time ./v2 N? 50000 Value of Pi is: 3.14151 real 0m31.313s user 0m26.898s No appreciable change, why? sys 0m0.012s
Quiz Q. The execution time for each of the two versions is not appreciably different because: A Multiplication does not take very large time, it is the division operation and the addition operation which is time consuming B since i and j are varying, computing i*i, j*j each takes much longer than N*N C Our program somehow figures that N is not changing, so it calculates N*N only once and uses that value repeatedly D I do not know and also cannot guess
Further reduction in execution time • We observe that the major computation is happening during evaluation of if condition if (i*i+j*j<=N*N) count=count+1 • This computation is done within a nested iteration, each running N times. (so N2 times) • We notice that the value of N is fixed during all iterations, so why calculate N*N again and again? • Instead of considering the square, we can consider only a triangle (half of square) with area Pi/8 • This will reduce computations by half
Modified program version 3 … n2 = N*N; count=0; for (i=1;i<=N;i=i+1){ for (j=i;j<=N;j=j+1){ if (i*i+j*j<=n2) count=count+1; }; }; pi=8.0*count/n2; cout << endl << "Value of Pi is: “ cout << pi << "\n"; return 0;
Execution results … [dbp@localhost cpp]$ time ./v3 N? 20000 Value of Pi is: 3.14153 real 0m4.301s user 0m2.132s sys 0m0.008s [dbp@localhost cpp]$ time ./v3 N? 50000 Value of Pi is: 3.14157 real 0m17.216s user 0m13.461s sys 0m0.012s Appreciable reduction
Time complexity of an algorithm • There are two ways of looking at the time taken by a program to execute. • Micro-view • We look at the time taken by each instruction in the program to execute, and the number of times that instruction is executed. • While the machine executes instructions in few tens of microseconds, or even in hundreds of nanoseconds, every instruction takes a different amount of time depending upon its nature • A ‘unit’ time can be used to represent comparative execution times
Some hypothetical comparative execution times • Assignment 1 unit • Addition/subtraction 2 • Multiplication 3 • Division 5 • Comparison 3 • Floating point operation 5 times int • Some other operations which we have not yet studied, such as reading from disk, or assignment to an array element, take longer time • Calculating value of index expression, e.g. A[3*i+j]
Time complexity of an algorithm … • If there is an iteration which executes N times, where N is an input value • If N largely determines the amount of computations in a program, we call it the ‘size’ of the problem • Number of computations are expressed in terms of N. For our Pi calculations, these may be, say, 24 N2 + 78 N + 183 • In general aN2 + bN + c
Time complexity, Macro view • When comparing two algorithms, we can get such expressions for each, and then compare for specific values of N • Consider prog1, and prog2, with time complexity: Prog1: 24 N2 + 78 N + 183 Prog2: 12586 N + 6453 • Prog1 will run faster than prog2 up to a certain N (What is that value?) • But for all values of N greater than this threshold, prog2 will always run faster
Time complexity, Macro view … • It is customary to compare algorithms on the basis of their behaviour for very large values of N [ Limit as N infinity] • Thus Prog1 is order N2, or O(N2) Prog2 is order N, or O(N) • In general, our effort should be • Try to reduce the order of complexity • Within the same order, try to reduce the coefficients of the expression