Sonoma State University | ||
Algorithm Analysis
|
||
Instructor: Henry M. Walker
Lecturer, Sonoma State University |
Although CS 415 has been well developed for several years, last year the CS faculty made a significant, long-term curricular change regarding SSU's Upper Division GE Area B Requirement.
Historically, CS Majors could satisfy this requirement by taking CS 454, Theory of Computation, and CS 454 will continue in this role for the next several semesters.
At some time in the future (but not Spring 2025), CS 415, Algorithm Analysis, will allow students to satisfy SSU's Upper Division GE Area B Requirement.
During an anticipated time of transition:
For future semesters, students should check with the CS faculty regarding which course(s) (CS 415 and/or CS 454) will satisfy SSU's Upper Division GE Area B Requirement.
This assignment focuses upon:
For reference and study, this assignment also contains reasonably-detailed analyses and discussion of two C++ functions.
In analyzing code throughout this assignment, you should use the following constants for the time it takes a machine to do specific operations:
+
or -
)
*
, /
or %
)
x++
is largely equal to x = x + 1
, P is roughly equal to A + S]
Note Looking Ahead: Although much of the course will use code analysis to study how well an algorithm will scale according to a size n, this assignment focuses only on analysis basics. Uses of analysis to predict scaling and run times will be examined in later assignments.
Download the file analysis.tar.gz, and decompress it with the line
tar -xvf analysis.tar.gz
Upon decompression, a new directory analysis should have been created containing these files organized into three groups:
loop.hpp
TestAnalysis.cpp
run1.cpp, ... run5.cpp
)
loopCount.hpp
TestAnalysisCount.cpp
run1Count.cpp, ... run5Count.cpp
)
Makefile
that allows easy compiling and linking
of the files to yield either of two complete programs.
To compile either program TestAnalysis.cpp
or TestAnalysisCount.cpp
,
use the corresponding line below:
make TestAnalysis make TestAnalysisCount
To run this code, either program uses command-line input with two arguments.
For example, to run the TestAnalysis
program for Exercise 0 with n=100, you would
type
./TestAnalysis 0 100
To illustrate how you are expected to write up code analysis within this
assignment, the following narrative presents sample assignment
instructions and expected student answers for the Exercises that
follow.
(Note: Although answers to typical questions/instructions are already given, a
separate section at the end of this Exercise 0 presents additional questions for
you to answer.)
#include "loop.hpp" long run0(int n) { long sum = 0; /* line 1 */ for (int i=0 ; i < n ; i++) { /* line 2 */ sum++; /* line 3 */ } return sum; }
Proposed Answer
Proposed Answer
Adding the results from part a:
total time = A + A + (n+1)(B) + (n)(P) + (n)(P)
combining constants and factors of n yields:
total time = (2A+B) + n((B+2P)
Proposed Answer
Big-O, Big-Ω, and Big-Θ all focus on the highest
degree term in a micro-analysis.
In this case, that term is n(B+2P)
In this expression, B and P are all constants, so adding
them might give a new constant Q = B+2P
Since one normally ignores constants in writing Big-O,
Big-Ω, and Big-Θ, any of the following would be
correct): O(Qn), O(n), Ω(Qn),
Ω(n), Θ(Qn), Θ(n).
Proposed Answer
From above we have total time = (2A+B) + n((B+2P)
To count the number of assignments, we could consider the
total time expression, with A=1 and B=P=0. That is A being
1 counts the number of assignments and the other constants
being 0 ignore those counts. Thus, to answer this question:
From above we have total time = (2A+B) + n((B+2P)
As an
experimental check of the counts in the previous step, consider
the number of assignments, Boolean operators, and increments,
when n = 100. Substitute 100 for n in the answers in the
previous step. Then compile and
run TestAnalysisCount.cpp
for this exercise 0 and
n=100:
make TestAnalysisCount ./TestAnalysisCount 0 100
Proposed Answer
Running this program yields these results:
Program to run loop-based code segments Running Exercise 0 with time iterations = 100 operation couts assignments: 2 Bool.ops: 101 + or - ops: 0 *, /, % ops: 0 increments: 200 sum returned: 100
Compare the counts from your analysis with the values obtained from the program. To what extent are they the same or different?
Proposed Answer
These numbers correspond exactly to the results in the previous
exercise step.
In function run0
, how does the value
of sum
relate to the execution of the loop body?
In Step a, line 2, above, why is the count for Boolean comparisons is one more than the number of increments?
Examine the augmented
function: run0Count.cpp,
which includes variables to count the number of assignments,
Boolean comparisons, etc. For example, at the start of the
function. all count variables are initialized to 0, and the
statement ++(*ACt)
increments the count of
assignments (A's) by 1.
int *
?
(++(*BCt))&&(i < n)Another possibility might reverse the order of these two conditions:
(i < n&&(++(*BCt)))Would either of these statements work, or might one give an incorrect answer? Explain.
try---catch
block. What is the purpose of
this extended block, and why are there two catch
blocks?
#include "loop.hpp" long run1(int n) { long sum = 0; /* line 1 */ for (int i=0 ; i < 6*n ; i+=2) /* line 2 */ sum++; /* line 3 */ return sum; }
As in Exercise 0, note that no Common Computational Formulae are required for this exercise.
Note: In your answer, be sure to give a separate time required for each line of the code. Likely, the amount of time for a line will involve some expression involving at least some of the variables n, A, B, S, M, and P.
Once time is determined for each line, add to obtain the total time needed.
Use your result for the total time to determine the Big-O, Big-Ω, and Big-Θ running times for run1, and explain your conclusions. For example, you likely will want to highlight which terms will dominate for large n and which will have minimal impact on the total time.
If instead of a time computation, use your answer in Step c to determine how many assignments, how many Boolean operations, how many additions, and how many multiplications are performed in this code, based on the number n?
As an experimental check of the counts in the previous step,
consider the number of assignments, Boolean operators, and
increments, when n = 100. Substitute 100 for n in the answers in
the previous step. Then compile and
run TestAnalysisCount.cpp
for this exercise 0 and
n=100:
make TestAnalysisCount ./TestAnalysisCount 1 100
Compare the counts from your analysis with the values obtained from the program. To what extent are they the same or different?
#include "loop.hpp" long run2(int n) { long sum = 0; /* line 1 */ for (int i=0 ; i < n ; i++) { /* line 2 */ sum++; /* line 3 */ } for (int j=n ; j < 2*n ; j++) { /* line 4 */ sum++; /* line 5 */ } return sum; }
The questions for Exercise 2 are the same as for Exercise 1, except
you need to analyze function run2
. Also, as in
Exercises 0 and 1, note that
no Common Computational
Formulae are required for this exercise.
#include "loop.hpp" long run3(int n) { long sum = 0; /* line 1 */ for (int i = 1 ; i <= n*n ; i++ ) { /* line 2 */ for (int j = 1; j <= i*i*i; j++) { /* line 3 */ sum++; /* line 4 */ } } return sum; }
This function contains two elements that are quite different from the previous examples.
i
from the outer loop.
Even with these substantial differences between this function and the previous functions, the analysis that follows utilizes the same overall structure as Exercise 0: first, this a narrative presents questions/instructions with answers, and a separate section of questions is given at the end for your responses.
As you will see, the questions here are analogous to those earlier in this assignment, but parts of the answers are quite different.
Note: In your answer, be sure to give a separate time required for each line of the code. Likely, the amount of time for a line will involve some expression involving at least some of the variables n, A, B, S, M, and P.
Proposed Answer
for
loop
for
loopi
i
Altogether for a given i, the amount of work is A +
(i3+1)(B+2M+P) + (i3)(P)
Grouping the constants (no
i's) and the powers
of i,
the total time is
(A+B+2M)
+ (i3)(B+2M+2P)
From the outer loop, the loop body ia executed n2 times, with i taking on the values 1, . . , (n2) within that loop.
For each i, the constant term (A+B+2M) is performed once, so the total amount of time corresponding to that term over all i's is (n2)(A+B+2M).
As i takes on values 1, . . , (n2), the
term containing i for the inner loop yields the amount
((13)(B+2M+2P) + (23)(B+2M+2P) +
(33)(B+2M+2P) + . . . + ((n2)3)(B+2M+2P).
Overall, combining the constant term and the terms
involving i, the total time for lines 3 and 4 is
(n2)(A+B+2M)
+
{[(13)(B+2M+2P)
+ (23)(B+2M+2P) +
(33)(B+2M+2P) + . . . +
(n2)3](B+2M+2P)}
Factoring out (B+2M+2P) in the above sum yields (n2)(A+B+2M) + {[(13) + (23) + (33) + . . . + ((n2)3)](B+2M+2P)}
Once time is determined for each line, add to obtain the total time needed.
Proposed Answer
Adding the results from part a:
total time = A + A + (n2+1)(B+M)) + (n2)(P) +
(n2)(A+B+2M) + (n2)(P) +
[(n2)2(n2+1)2 / 4] (B+2M+2P)
multiplying out the squaring operation in the last term yields:
total time = A + A + (n2+1)(B+M)) + (n2)(P) +
(n2)(A+B+2M) + (n8)(B+2M+2P)/4) +
(n6(2(B+2M+2P)/4) + (n4)((B+2M+2P) / 4)
Combining constants and powers of n yields:
(2A+B+M) + (n2)(A+2B+3M+P)+ (n4)((B+2M+2P) / 4)
+ (n6)((B+2M+2P)/2) + (n8)((B+2M+2P) / 4)
Use your result for the total time to determine the Big-O, Big-Ω, and Big-Θ running times for run3, and explain your conclusions. For example, you likely will want to highlight which terms will dominate for large n and which will have minimal impact on the total time.
Proposed Answer
In reviewing this algebraic formula, the highest or dominant
power of n is (n8), so this function has
O(n8), Ω(n8), and Θ(n8).
If instead of a time computation, we could ask now many assignments, how many Boolean operations, how many additions, and how many multiplications are performed in this code? Give both a general count and the count when n = 10.
Proposed Answer
From above we have total time
= (2A+B+M) + (n2)(A+2B+3M+P)+ (n4)((B+2M+2P) / 4)
+ (n6)((B+2M+2P)/2) + (n8)((B+2M+2P) / 4)
To count the number of assignments, we could consider the
total time expression, with A=1 and B=P=0. That is A being
1 counts the number of assignments and the other constants
being 0 ignore those counts. Thus, to answer this question:
Category | General Count | Count when n = 10 |
---|---|---|
assignments (A) | 2 + n2 | 2+100 = 102 |
Boolean ops (B) | 1 + 2n2 + n4/4 + n6/2 + n8/4 | 1 + 200 + 10000/4 + 1000000/2 + 100000000/4 = 25502701 |
Additions (S) | 0 | 0 |
Multiplications (M) | 1 + 3n2 + 2n4/4 + 2n6/2 + 2n8/4 | 1 + 300 + 5000 + 1000000 + 50000000 = 51005301 |
increments (P) | n2 + 2n4/4 + 2n6/2 + 2n8/4 | 100 + 5000 + 1000000 + 50000000 = 51005100 |
Compare your computations from the previous Step with the counts actually given by running TestAnalysisCount.cpp for this function when n = 10. To what extent do the counts agree, or do they differ by a litle, or by a lot? Explain briefly.
Proposed Answer
Running this program yields these results:
Program to run loop-based code segments Running Exercise 3 with time iterations = 10 operation couts assignments: 102 Bool.ops: 25502701 + or - ops: 0 *, /, % ops: 51005301 increments: 51005100 sum returned: 25502500
These numbers correspond exactly to the results in the previous exercise step.
Explain in your own words how the analysis in this code is determined. In particular,
Step c indicates that this function has O(n8), Ωn8), and Θn8). Write in your own words why this conclusion follows from the expression for the overall time determined in Step b.
On December 11, 2024, I gave this question (but not my naswers) to both Claude and ChatGPT. Both recognized that the inner loop involved a series. However,
#include "loop.hpp" long run4(int n) { long sum = 0; /* line 1 */ for (int i=1 ; i <= n*n ; i++) { /* line 2 */ for (int j=1 ; j <= n*n*n ; j++) { /* line 3 */ sum++; /* line 4 */ } } return sum; }
While questions for this exercise mostly are similar to those in Exercises 1 and 2, note there are a few changes.
Notes:
Once time is determined for each line, add to obtain the total time needed. As part of this answer, explain why no special common computational formulae are needed here. That is why is the analysis of this exercise rather different than that of Exercise 3?
Use your result for the total time to determine the Big-O, Big-Ω, and Big-Θ running times for run4, and explain your conclusions. For example, you likely will want to highlight which terms will dominate for large n and which will have minimal impact on the total time.
Instead of a time computation, determine how many assignments, how many Boolean operations, how many additions, and how many multiplications are performed in this code, based on the number n?
Extra Credit Option:
As an experimental check of the counts in the previous step,
consider the number of assignments, Boolean operators, and
increments, when n = 10. Substitute 10 for n in the answers in
the previous step. Then compile and
run TestAnalysisCount.cpp
for this exercise 4 and
n=10:
make TestAnalysisCount ./TestAnalysisCount 4 10Compare the counts from your analysis with the values obtained from the program. To what extent are they the same or different?
#include "loop.hpp" long run5(int n) { long sum = 0; /* line 1 */ for (int i = 1 ; i <= n ; i++ ) { /* line 2 */ for (int j = i-1; j <= i+3; j++) { /* line 3 */ sum++; /* line 4 */ } } return sum; }
Following the approach in Exercise 0, Step a, perform
a careful micro-analysis of the time required for each line of
this code.
Does this computation require the same type of
series as Exercise 3? Explain your answer.
Once time is determined for each line, add to obtain the total time needed. Does this answer require the use of a common computational formula? Explain briefly.
Use your result for the total time to determine the Big-O, Big-Ω, and Big-Θ running times for run5, and explain your conclusions. For example, you likely will want to highlight which terms will dominate for large n and which will have minimal impact on the total time.
Extra Credit Option: Instead of a time computation, determine how many assignments, how many Boolean operations, how many additions, and how many multiplications are performed in this code, based on the number n?
Extra Credit Option:
As an experimental check of the counts in the previous step,
consider the number of assignments, Boolean operators, and
increments, when n = 10. Substitute 10 for n in the answers in
the previous step. Then compile and
run TestAnalysisCount.cpp
for this exercise 5 and
n=10:
make TestAnalysisCount ./TestAnalysisCount 5 10Compare the counts from your analysis with the values obtained from the program. To what extent are they the same or different?
created December 21, 2021 revised December-January 2021 revised Summer 2022 revised 1-2 January 2023 typos corrected 27 January 2023 updated Summer 2023 typo corrected 28 January 2024 largely rethought and rewritten 12-16 November 2024 |
|
For more information, please contact Henry M. Walker at walker@cs.grinnell.edu. |
Copyright © 2011-2025
by Henry M. Walker.
|