Sonoma State University
 
Algorithm Analysis
Instructor: Henry M. Walker

Lecturer, Sonoma State University
Professor Emeritus of Computer Science and Mathematics, Grinnell College

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.

Assignment on Analysis of Nonrecursive Algorithms

Summary

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:

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.

Preparation

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:

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

Exercise 0: Getting Started

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.)

Basic function: run0.cpp     Augmented function: run0Count.cpp
#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;
}

Sample Assignment Instructions and Expected Answers

  1. Perform a careful micro-analysis of the time required for each line of this code (ignore both the function call itself and the return).

    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

  2. After computing the time for each line in Step a, add to obtain the total time needed.

    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)

  3. 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.

    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).

  4. If instead of a time computation, we could ask many assignments, how many Boolean operations, how many additions, and how many multiplications are performed in this code?

    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:

  5. 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
          
  6. 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.

Answer these Questions for Exercise 0 (no need to comment on the above sample questions or answers)

  1. In function run0, how does the value of sum relate to the execution of the loop body?

  2. In Step a, line 2, above, why is the count for Boolean comparisons is one more than the number of increments?

  3. 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.

Exercise 1

Basic function: run1.cpp     Augmented function: run1Count.cpp
#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;
}

Answer these Questions for Exercise 1

As in Exercise 0, note that no Common Computational Formulae are required for this exercise.

  1. Following the approach in Exercise 0, Step a, perform a careful micro-analysis of the time required for each line of this code.

    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.

  2. Once time is determined for each line, add to obtain the total time needed.

  3. 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.

  4. 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?

  5. 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
        
  6. Compare the counts from your analysis with the values obtained from the program. To what extent are they the same or different?

Exercise 2

Basic function: run2.cpp     Augmented function: run2Count.cpp
#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;
}

Answer these Questions for Exercise 2

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.

Exercise 3

Basic function: run3.cpp     Augmented function: run3Count.cpp
#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;
 }

Sample Assignment Instructions and Expected Answers

This function contains two elements that are quite different from the previous examples.

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.

  1. Following the approach in Exercise 0, Step a, perform a careful micro-analysis of the time required for each line of this code.

    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

  2. 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)

  3. 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).

  4. 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

  5. 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.

Answer these Questions for Exercise 3 (no need to comment on the above sample questions or answers)

  1. Explain in your own words how the analysis in this code is determined. In particular,  

  2. 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.

Observation/Warning about Results from Claude and ChatGPT

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,

Exercise 4

Basic function: run4.cpp     Augmented function: run4Count.cpp
#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;
}

Answer these Questions for Exercise 4

While questions for this exercise mostly are similar to those in Exercises 1 and 2, note there are a few changes.

  1. Following the approach in Exercise 0, Step a, perform a careful micro-analysis of the time required for each line of this code.

    Notes:

  2. 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?

  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.

  4. 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?

  5. 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 10
        
    Compare the counts from your analysis with the values obtained from the program. To what extent are they the same or different?

Exercise 5

Basic function: run5.cpp     Augmented function: run5Count.cpp
#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;

}

Answer these Questions for Exercise 5

  1. 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.

  2. 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.

  3. 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.

  4. 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?

  5. 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 10
        
    Compare 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
Valid HTML 4.01! Valid CSS!
For more information, please contact Henry M. Walker at walker@cs.grinnell.edu.
ccbyncsa.png

Copyright © 2011-2025 by Henry M. Walker.
Selected materials copyright by Marge Coahran, Samuel A. Rebelsky, John David Stone, and Henry Walker and used by permission.
This page and other materials developed for this course are under development.
This and all laboratory exercises for this course are licensed under a Creative Commons Attribution-NonCommercial-Share Alike 4.0 International License.