From 48df3b0941fdebefe1394882180c25a878d51120 Mon Sep 17 00:00:00 2001 From: Jules Date: Thu, 9 Jul 2020 22:54:34 +0200 Subject: [PATCH 1/3] C solutions initial --- c/p001.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 c/p001.c diff --git a/c/p001.c b/c/p001.c new file mode 100644 index 0000000..cc5ade9 --- /dev/null +++ b/c/p001.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include +#include + +// Trivial solution +size_t getSum(size_t max) +{ + size_t retVal = 0; + for (size_t i = 1; i < max; ++i) + if (i % 3 == 0 || i % 5 == 0) + retVal += i; + return retVal; +} + +// Trick: +// First Get the number of elements divisible by 3, 5, and 15 +// 15 because for example 30 is both divible by 3 and 5 +// and we are not allowed to count 30 twice. +// Now use the sum rule: sum of integers going from 0 to n is equal to 1/2 * (n * (n+1)) +// The total number of multiples of 3 in max is (max - 1) / 3. +// Minus 1, because max itself is not included +// The sum of all numbers divisible by 3 is then sum of all mutiples of 3 under max. +// Repeat it for 5 and substract the sum of all multiples of 15 to get the result +size_t getSum2(size_t max) +{ + size_t limit = max - 1; + int numb5 = limit / 5; + int numb3 = limit / 3; + int numb15 = limit / 15; + return (5 * (numb5 * (numb5 + 1)) + (3 * (numb3 * (numb3 + 1))) - (15 * (numb15 * (numb15 + 1)))) / 2; + +} + + +/* + * The funny thing is that the first getSum() generate less assembly code than the getSum2(). + * However when benchmarking, the second function didn't even run because of the lack of branch predictions. This will make it faster + */ +int main(int argc, char** argv) +{ + size_t max = 1000; + printf("Result: %lu\n", getSum(max)); + printf("Smarter Result: %lu\n", getSum2(max)); + + return 0; +} + From 3287aaad6dbfa92c0463fd369a812b30eab98c0c Mon Sep 17 00:00:00 2001 From: AKJ7 <39413010+AKJ7@users.noreply.github.com> Date: Thu, 9 Jul 2020 23:25:40 +0200 Subject: [PATCH 2/3] Update p001.c Better description --- c/p001.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/c/p001.c b/c/p001.c index cc5ade9..a718ddd 100644 --- a/c/p001.c +++ b/c/p001.c @@ -26,17 +26,17 @@ size_t getSum(size_t max) size_t getSum2(size_t max) { size_t limit = max - 1; - int numb5 = limit / 5; - int numb3 = limit / 3; - int numb15 = limit / 15; + size_t numb5 = limit / 5; + size_t numb3 = limit / 3; + size_t numb15 = limit / 15; return (5 * (numb5 * (numb5 + 1)) + (3 * (numb3 * (numb3 + 1))) - (15 * (numb15 * (numb15 + 1)))) / 2; - } - /* - * The funny thing is that the first getSum() generate less assembly code than the getSum2(). - * However when benchmarking, the second function didn't even run because of the lack of branch predictions. This will make it faster + * Reading the assembly ouput of getSum() and getSum2(), one might be tricked into thinking that getSum() is faster because it generated 6 assemnly + * lines less. It is however very slow because of the branches (from the for loop and the checks if the number is a mutliple of 3 or 5) which would + * definitely lead to false branch predictions. + * When benchmarking, getSum() takes longer and longer, as the while loop increases while getSum2() finishes at a constant time of a couple of milliseconds. */ int main(int argc, char** argv) { From 869b0fe66588b59db9ffcfc925b57a011501f69c Mon Sep 17 00:00:00 2001 From: AKJ7 <39413010+AKJ7@users.noreply.github.com> Date: Thu, 9 Jul 2020 23:26:04 +0200 Subject: [PATCH 3/3] Update p001.c Better description