Created
August 13, 2019 10:33
-
-
Save jtsagata/bc9f720242dfa1b046760bbec0633d46 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Nat = unsigned long long; | |
Nat naive_sum(Nat div1, Nat div2, Nat user_value) { | |
Nat sum{}; | |
for (Nat i = 0; i <= user_value; i++) { | |
if ((i % div1 == 0) || (i % div2 == 0)) { | |
sum = sum + i; | |
} | |
} | |
return (sum); | |
} | |
#include <cassert> | |
#include <numeric> | |
#include <utility> | |
using Nat = unsigned long long; | |
int main() { | |
// In normal code this is better to be a template function | |
// but here a generic lambda will do, | |
// BUT! you need a C++20 compiler. gcc 7.4.0 can do it, clang++9 cant't do it yet | |
// The problem is the std::pair<auto, auto>, this can be solved with a template func, | |
// Or by simply not using generic code :-) | |
constexpr auto orSum = [](std::pair<auto, auto> divs, auto max) { | |
auto div1 = divs.first; | |
auto div2 = divs.second; | |
// Just for safety, make aware and explicit about narrow conversions | |
static_assert(std::is_unsigned<typeof(div1)>::value, "orSum args are unsigned integers"); | |
static_assert(std::is_unsigned<typeof(div2)>::value, "orSum args are unsigned integers"); | |
static_assert(std::is_unsigned<typeof(max)>::value, "orSum args are unsigned integers"); | |
// Calculate the sum of dividers. It's a pure function so constexpr | |
// implement as a lambda, as it is for function internal use only | |
constexpr auto kSum = [](auto div, auto max) { | |
auto m = max / div; | |
return m * (m + 1) / 2 * div; | |
}; | |
// Solve the easy co-prime numbers problem | |
auto gcd = std::gcd(div1, div2); | |
max = max / gcd, div1 = div1 / gcd, div2 = div2 / gcd; | |
auto s = kSum(div1, max) + kSum(div2, max) - kSum(div1 * div2, max); | |
// And now solve the non co-prime problem | |
return s * gcd; | |
}; | |
// Brute force assertions, it will handle all special cases (i hope) :-) | |
for (Nat i = 1; i < 100; i++) { | |
for (Nat j = 1; j < 100; j++) { | |
// Note that by using std::pair it's hard to make mistakes | |
// is it supposed to be called with (100,3,5) or (3,5,100); | |
// no linter or compiler can help you with this | |
auto r = orSum(std::pair{i, j}, Nat{10000}); | |
assert(r == naive_sum(i, j, 10000)); | |
} | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment