Reputation: 11
I've compared two algorithms to calculate binomial coefficient C(n, k) as below: #1 is derived from the formulaic definition of the binomial coefficient to calculate, #2 uses dynamic programming.
#include <stdio.h>
#include <sys/time.h>
#define min(x, y) (x<y?x:y)
#define NMAX 150
double binomial_formula(int n, int k) {
double denominator=1, numerator=1, i;
for (i = 0; i< k; i++)
numerator *= (n-i), denominator *= (i+1);
return numerator/denominator;
}
double binomial_dynamic_pro(int n, int k) {
double c[NMAX][NMAX];
int i,j;
for (i = 0; i <= n; i++) {
for (j = 0; j <= min(i, k); j++) {
if (i == j || j == 0)
c[i][j] = 1;
else
c[i][j] = c[i-1][j-1]+c[i-1][j];
}
}
return c[n][k];
}
int main(void) {
struct timeval s, e;
int n = 50, k = 30;
double re = 0;
printf("now formula calc C(%d, %d)..\n", n, k);
gettimeofday(&s, NULL);
re = binomial_formula(n, k);
gettimeofday(&e, NULL);
printf("%.0f, use time: %ld'us\n", re,
1000000*(e.tv_sec-s.tv_sec)+ (e.tv_usec-s.tv_usec));
printf("now dynamic calc C(%d, %d)..\n", n, k);
gettimeofday(&s, NULL);
re = binomial_dynamic_pro(n, k);
gettimeofday(&e, NULL);
printf("%.0f, use time: %ld'us\n", re,
1000000*(e.tv_sec-s.tv_sec)+ (e.tv_usec-s.tv_usec));
return 0;
}
and I use gcc to compile, and it runs out like this:
now formula calc C(50, 30)..
47129212243960, use time: 2'us
now dynamic calc C(50, 30)..
47129212243960, use time: 102'us
These results are unexpected for me. I thought that dynamic programming should be faster, for it's O(nk)
, but the formula's method should be O(k^2)
and it uses multiplication, which should be also be slower.
So why is the dynamic programming version so much slower?
Upvotes: 0
Views: 435
Reputation: 3191
First algorithm
Second algorithm
In terms of time/space, first algorithm is better but the second algorithm has the advantage of computing answer for smaller values as well; it can be used as a pre-processing step.
Imagine that you are given a number of queries of the form n k
and you are asked to write n choose k
for each of them. Further, imagine that the number of queries is big (say around n*n
). Using the first algorithm takes O(nq) = O(n*n*n)
while using the second algorithm takes O(n*n)
.
So it all depends on what you are trying to do.
Upvotes: 0
Reputation: 9770
binomial_formula
as written is definitely not O(k^2)
. It only has a single loop which is of size k
making it O(k)
. You should also keep in mind that on modern architectures that the cost of memory accesses dwarf the cost of any single instruction by an order of magnitude, and your dynamic programming solution reads and writes many more addresses in memory. The first version can be computed entirely in a few registers.
Note that you can actually improve on your linear version by recognizing that C(n,k) == C(n, n-k):
double binomial_formula(int n, int k) {
double delominator=1, numerator=1, i;
if (k > n/2)
k = n - k;
for (i = 0; i< k; i++)
numerator *= (n-i), delominator *= (i+1);
return numerator / delominator;
}
You should keep in mind that dynamic programming is just a technique and not a silver bullet. It doesn't magically make all algorithms faster.
Upvotes: 2