Skip to content

Instantly share code, notes, and snippets.

@jtsagata
Created August 13, 2019 10:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jtsagata/bc9f720242dfa1b046760bbec0633d46 to your computer and use it in GitHub Desktop.
Save jtsagata/bc9f720242dfa1b046760bbec0633d46 to your computer and use it in GitHub Desktop.
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