The runtime is measured for all the methods using chrono standard library. To make the program stop after a certain amount of time, I have a while (1) loop that either stops when the max time has been reached or when all elements till n is executed in the loop. An example of the implementation is shown below (for naïve recursive method). I would recommend running the program with maxsize = 40 as the numbers start to wrap even when using long long as the data type. One can enter maxSize = 40 and time = 1 to see that the program stops after 1s.
A table with the time taken for each method is made in a four different data files “naive.txt”, “bottom.txt”, “closed.txt”, “closed.txt”, and “matrix.txt” for naïve recursive method, bottom up method, closed form method, and matrix representation method respectively. The file should be created after the program “5_1b.cpp” is compiled and executed. I am using the “Power of Number” method while computing the power of terms in my matrix and closed form calculation in order to reach time complexity of .
A table for the ‘n’ (in this case going from 1 to 40 because the data needs to fit in one page!) and the time taken to compute the Fibonacci series for the different methods. The time is calculated in nanoseconds! We notice that the time taken to compute the Fibonacci series gets considerably larger for the Naïve Recursive method (when comparting to the other data types).
For the same value of n, all four methods might not return the same Fibonacci number! This is because, as the value of n gets larger and closer to infinity, the Closed Form approach contain floating-point errors. We use the equation involving the terms and as a long double values, then subtract neg from pos, compute the power of the term to n, then finally divide the term by the square root of 5! This value may round off certain terms based on the property and size of the data type “double”, which may give possible errors.
d.
The graph has been plotted using gnuplot. To get the graph, one must type “gnuplot plot.plt” into the terminal. I have attached a picture of the graph below (and also in my zip file for reference). The graph shows that Naïve Recursive takes exponential time (the most). The graph is made with logarithmic scales so that the values can be seen clearly.
Time complexity for the following methods:
Naïve Recursive:
Closed Form: when using the “power of number” recursion
Bottom Up Approach:
Matrix Representation:
Problem 5.2
(I took help from https://people.eecs.berkeley.edu/~vazirani/algorithms/chap2.pdf)
a.
let firstNum = 1011
let secondNum = 11010
let sum = 0;
let tempSum = 0;
let totalSum = 0;
for i = 1 upto lengthof.firstNum
for j = 1 upto lengthof.secondNum
ans = firstNum[j] * secondNum[i]
bitshift ans << j-1
sum += ans;
tempSum += ans << i-1
totalSum += tempSum;
//time complexity for one multiplicatin is n. There
are two nested loops running n times, therefore,
time complexity is bigO (n^2).
b.
//assume n to be a power of 2 = even
let firstNum = 11100111
let secondNum = 1101
divAndConq (firstElem, secondElem) {
int len = maximumOf(lengthof.firstElem, lengthof.secondElem)
if (len == 1) {
return firstElem * secondElem
}
else {
firstL = left [0 - lengthof.firstElem/2]
firstR = right [(lengthof.firstElem/2)+1 - lengthof.firstElem]
secondL = left [0 - lengthof.secondElem/2]
secondR = right [(lengthof.secondElem/2)+1 - lengthof.secondElem]
return Mult1*2^n + (temp-Mult1-Mult2) * 2^n/2 + Mult2 //multiplied by 2^n to bit shift
}
}
c.
The recurrence for the time complexity of the Divide and Conquer algorithm was created by looking at the tree I made in question 5.2b and the recurrence tree made in question 5.2c.