diff --git a/contents/approximate_counting/approximate_counting.md b/contents/approximate_counting/approximate_counting.md index 917e79922..b82a0f6fb 100644 --- a/contents/approximate_counting/approximate_counting.md +++ b/contents/approximate_counting/approximate_counting.md @@ -360,6 +360,8 @@ As we do not have any objects to count, we will instead simulate the counting wi {% method %} {% sample lang="jl" %} [import, lang:"julia"](code/julia/approximate_counting.jl) +{% sample lang="c" %} +[import, lang:"c"](code/c/approximate_counting.c) {% sample lang="cpp" %} [import, lang:"cpp"](code/c++/approximate_counting.cpp) {% endmethod %} diff --git a/contents/approximate_counting/code/c/approximate_counting.c b/contents/approximate_counting/code/c/approximate_counting.c new file mode 100644 index 000000000..ded7a518e --- /dev/null +++ b/contents/approximate_counting/code/c/approximate_counting.c @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include + +// This function returns a pseudo-random number between 0 and 1 +double drand() +{ + return (double)rand() / RAND_MAX; +} + +// This function takes +// - v: value in register +// - a: a scaling value for the logarithm based on Morris's paper +// It returns the approximate count +double n(double v, double a) +{ + return a * (pow(1 + 1 / a, v) - 1); +} + +// This function takes +// - v: value in register +// - a: a scaling value for the logarithm based on Morris's paper +// It returns a new value for v +double increment(double v, double a) +{ + // delta is the probability of incrementing our counter + double delta = 1 / (n(v + 1, a) - n(v, a)); + + if (drand() <= delta) { + return v + 1; + } + return v; +} + +// This function simulates counting and takes +// - n_items: number of items to count and loop over +// - a: a scaling value for the logarithm based on Morris's paper +// It returns n(v, a), the approximate count +double approximate_count(size_t n_items, double a) +{ + int v = 0; + for (size_t i = 0; i < n_items; ++i) { + v = increment(v, a); + } + + return n(v, a); +} + +// This function takes +// - n_trials: the number of counting trials +// - n_items: the number off items to count +// - a: a scaling value for the logarithm based on Morris's paper +// - threshold: the maximum percent error allowed +// It terminates the program on failure +void test_approximation_count(size_t n_trials, size_t n_items, double a, + double threshold) +{ + double sum = 0.0; + for (size_t i = 0; i < n_trials; ++i) { + sum += approximate_count(n_items, a); + } + double avg = sum / n_trials; + + assert(fabs((avg - n_items) / n_items) < threshold); +} + +int main() +{ + srand(time(NULL)); + + printf("Counting Tests, 100 trials\n"); + printf("testing 1000, a = 30, 1%% error\n"); + test_approximation_count(100, 1000, 30, 0.1); + printf("testing 12345, a = 10, 1%% error\n"); + test_approximation_count(100, 12345, 10, 0.1); + printf("testing 222222, a = 0.5, 10%% error\n"); + test_approximation_count(100, 222222, 0.5, 0.2); + + return 0; +}