project-euler

https://projecteuler.net/
Log | Files | Refs | README

EulerUtility.cpp (9668B)


      1 #include <fstream>
      2 #include <numeric>
      3 #include <regex>
      4 #include <sstream>
      5 #include <unordered_set>
      6 
      7 #include "EulerUtility.h"
      8 
      9 int EulerUtility::multiply(int x, int y)
     10 {
     11     return x * y;
     12 }
     13 
     14 int EulerUtility::sumOfDivisors(int n)
     15 {
     16     int prod = 1;
     17 
     18     for(int k = 2; k * k <= n; ++k)
     19     {
     20         int p = 1;
     21 
     22         while(n % k == 0)
     23         {
     24             p = p * k + 1;
     25             n /= k;
     26         }
     27 
     28         prod *= p;
     29     }
     30 
     31     if(n > 1)
     32         prod *= 1 + n;
     33 
     34     return prod;
     35 }
     36 
     37 std::vector<int> EulerUtility::getPrimesUnderCeiling(int ceiling)
     38 {
     39     std::vector<int> primes;
     40 
     41     primes.push_back(2);
     42     primes.push_back(3);
     43 
     44     bool is_prime;
     45 
     46     for(int i = 5; i < ceiling; i += 2)
     47     {
     48         is_prime = true;
     49 
     50         for(int j = 3; j * j <= i && is_prime; j += 2)
     51             if(i % j == 0) is_prime = false;
     52 
     53         if(is_prime)
     54             primes.push_back(i);
     55     }
     56 
     57     return primes;
     58 }
     59 
     60 std::vector<int> EulerUtility::getPrimesUnderCeilingIndexed(int ceiling)
     61 {
     62     std::vector<int> primes = { -1, -1, 2, 3, -1 };
     63 
     64     bool is_prime;
     65 
     66     for(int i = 5; i < ceiling; i += 2)
     67     {
     68         is_prime = true;
     69 
     70         for(int j = 3; j * j <= i && is_prime; j += 2)
     71             if(i % j == 0) is_prime = false;
     72 
     73         if(is_prime)
     74         {
     75             primes.push_back(i);
     76             primes.push_back(-1);
     77         }
     78         else
     79         {
     80             primes.push_back(-1);
     81             primes.push_back(-1);
     82         }
     83     }
     84 
     85     return primes;
     86 }
     87 
     88 std::vector<int> EulerUtility::tokenizer(std::string s, char delim)
     89 {
     90     std::istringstream split(s);
     91     std::vector<int> tokens;
     92     for (std::string each; std::getline(split, each, delim); tokens.push_back(atoi(each.c_str())));
     93 
     94     return tokens;
     95 }
     96 
     97 std::vector<std::string> EulerUtility::strTokenizer(std::string s, char delim)
     98 {
     99     std::istringstream split(s);
    100     std::vector<std::string> tokens;
    101     for (std::string each; std::getline(split, each, delim); tokens.push_back(each));
    102 
    103     return tokens;
    104 }
    105 
    106 std::vector<int> EulerUtility::factorialDigits(int n)
    107 {
    108     std::vector<int> digits(1, 1);
    109 
    110     for (int i = 1; i <= n; ++i)
    111     {
    112         for (unsigned j = 0; j < digits.size(); ++j)
    113             digits[j] *=i;
    114 
    115         for (unsigned j = 0; j < digits.size(); ++j)
    116         {
    117             if (digits[j] >= 10)
    118             {
    119                 int carry = (digits[j] - (digits[j] % 10)) / 10;
    120                 digits[j] = digits[j] % 10;
    121 
    122                 if (j == digits.size() - 1)
    123                     digits.push_back(carry);
    124                 else
    125                     digits[j + 1] += carry;
    126             }
    127         }
    128     }
    129 
    130     return digits;
    131 }
    132 
    133 std::vector<int> EulerUtility::powerDigits(int n, int p)
    134 {
    135     std::vector<int> digits = intToDigits(n);
    136     std::reverse(digits.begin(), digits.end());
    137 
    138     for (int i = 1; i < p; ++i)
    139     {
    140         for (unsigned j = 0; j < digits.size(); ++j)
    141             digits[j] *=n;
    142 
    143         for (unsigned j = 0; j < digits.size(); ++j)
    144         {
    145             if (digits[j] >= 10)
    146             {
    147                 int carry = (digits[j] - (digits[j] % 10)) / 10;
    148                 digits[j] = digits[j] % 10;
    149 
    150                 if (j == digits.size() - 1)
    151                     digits.push_back(carry);
    152                 else
    153                     digits[j + 1] += carry;
    154             }
    155         }
    156     }
    157 
    158     return digits;
    159 }
    160 
    161 cpp_int EulerUtility::bigFactorial(cpp_int n) 
    162 {
    163     if (n == 0)
    164         return 1;
    165     return n * bigFactorial(n - 1);
    166 }
    167 
    168 int EulerUtility::factorial(int n) 
    169 {
    170     if (n == 0)
    171         return 1;
    172     return n * factorial(n - 1);
    173 }
    174 
    175 cpp_int EulerUtility::choose(int n, int k)
    176 {
    177     return EulerUtility::bigFactorial(n) / (EulerUtility::bigFactorial(k) * EulerUtility::bigFactorial(n - k));
    178 }
    179 
    180 bool EulerUtility::isPerfectSquare(llui n)
    181 {
    182     llui tst = (llui)(sqrt(n) + 0.5);
    183     return tst*tst == n;
    184 }
    185 
    186 bool EulerUtility::isPerfectCube(llui n)
    187 {
    188     llui tst = (llui)std::floor(std::pow(n, 1/3.) + 0.5);
    189     return n == tst * tst * tst;
    190 }
    191 
    192 std::vector<int> EulerUtility::intToDigits(int n)
    193 {
    194     std::vector<int> digitArray;
    195 
    196     while (n != 0)
    197     {
    198         digitArray.push_back(n % 10);
    199         n /= 10;
    200     }
    201 
    202     std::reverse(digitArray.begin(), digitArray.end());
    203 
    204     return digitArray;
    205 }
    206 
    207 std::vector<int> EulerUtility::lluiToDigits(llui n)
    208 {
    209     std::vector<int> digitArray;
    210 
    211     while (n != 0)
    212     {
    213         digitArray.push_back(n % 10);
    214         n /= 10;
    215     }
    216 
    217     std::reverse(digitArray.begin(), digitArray.end());
    218 
    219     return digitArray;
    220 }
    221 
    222 std::vector<int> EulerUtility::BigIntToDigits(cpp_int n)
    223 {
    224     std::vector<int> digitArray;
    225     export_bits(n, std::back_inserter(digitArray), 32);
    226 
    227     std::reverse(digitArray.begin(), digitArray.end());
    228 
    229     return digitArray;
    230 }
    231 
    232 int EulerUtility::digitsToInteger(std::vector<int> d)
    233 {
    234     std::stringstream ss;
    235 
    236     for (int i : d)
    237         ss << i;
    238 
    239     int integer;
    240     ss >> integer;
    241 
    242     return integer;
    243 }
    244 
    245 llui EulerUtility::digitsTollui(std::string s)
    246 {
    247     std::stringstream ss;
    248 
    249     for (char c : s)
    250         ss << c;
    251 
    252     llui digits;
    253     ss >> digits;
    254 
    255     return digits;
    256 }
    257 
    258 bool EulerUtility::hasUniqueDigits(int n, bool allowZero)
    259 {
    260     std::vector<int> digits = EulerUtility::intToDigits(n);
    261 
    262     std::unordered_set<int> uniqueDigits;
    263 
    264     for (int digit : digits)
    265     {
    266         if (digit == 0 && !allowZero)
    267             return false;
    268 
    269         uniqueDigits.insert(digit);
    270     }
    271 
    272     return digits.size() == uniqueDigits.size();
    273 }
    274 
    275 /* 
    276 * calculates (a * b) % c taking into account that a * b might overflow 
    277 */
    278 ll mulmod(ll a, ll b, ll mod)
    279 {
    280     ll x = 0,y = a % mod;
    281     while (b > 0)
    282     {
    283         if (b % 2 == 1)
    284             x = (x + y) % mod;
    285 
    286         y = (y * 2) % mod;
    287         b /= 2;
    288     }
    289 
    290     return x % mod;
    291 }
    292 
    293 /* 
    294 * modular exponentiation
    295 */
    296 ll modulo(ll base, ll exponent, ll mod)
    297 {
    298     ll x = 1;
    299     ll y = base;
    300 
    301     while (exponent > 0)
    302     {
    303         if (exponent % 2 == 1)
    304             x = (x * y) % mod;
    305 
    306         y = (y * y) % mod;
    307         exponent = exponent / 2;
    308     }
    309 
    310     return x % mod;
    311 }
    312 
    313 /*
    314 * Miller-Rabin primality test, iteration signifies the accuracy
    315 */
    316 bool EulerUtility::isPrime(ll p, int iteration)
    317 {
    318     if ((p < 2) || (p != 2 && p % 2 == 0))
    319         return false;
    320 
    321     ll s = p - 1;
    322 
    323     while (s % 2 == 0)
    324         s /= 2;
    325 
    326     for (int i = 0; i < iteration; i++)
    327     {
    328         ll a = rand() % (p - 1) + 1, temp = s;
    329         ll mod = modulo(a, temp, p);
    330 
    331         while (temp != p - 1 && mod != 1 && mod != p - 1)
    332         {
    333             mod = mulmod(mod, mod, p);
    334             temp *= 2;
    335         }
    336 
    337         if (mod != p - 1 && temp % 2 == 0)
    338             return false;
    339     }
    340 
    341     return true;
    342 }
    343 
    344 bool EulerUtility::isTriangle(int n)
    345 {
    346     return std::floor(sqrt(2 * n + 0.25) - 0.5) == sqrt(2 * n + 0.25) - 0.5;
    347 }
    348 
    349 bool EulerUtility::isPentagonal(llui n)
    350 {
    351     return isPerfectSquare((24 * n) + 1) && ((llui)sqrt((24 * n) + 1) + 1) % 6 == 0;
    352 }
    353 
    354 std::vector<std::string> EulerUtility::openWordFile(std::string filename)
    355 {
    356     std::ifstream file;
    357     std::vector<std::string> names;
    358     std::string name;
    359     file.open(filename);
    360 
    361     while(getline(file, name, ','))
    362         names.push_back(name.substr(1, name.size() - 2));
    363 
    364     return names;
    365 }
    366 
    367 cpp_int EulerUtility::power(cpp_int i, int p)
    368 {
    369     if (p <= 0)
    370         return 1;
    371 
    372     return i * power(i, p - 1);
    373 }
    374 
    375 int EulerUtility::digitalRoot(int n)
    376 {
    377     std::vector<int> digits = intToDigits(n);
    378     int digitSum = std::accumulate(digits.begin(), digits.end(), 0);
    379 
    380     if (digitSum > 9)
    381         return digitalRoot(digitSum);
    382 
    383     return digitSum;
    384 }
    385 
    386 int EulerUtility::digitalRoot(cpp_int n)
    387 {
    388     std::vector<int> digits = BigIntToDigits(n);
    389     int digitSum = std::accumulate(digits.begin(), digits.end(), 0);
    390 
    391     if (digitSum > 9)
    392         return digitalRoot(digitSum);
    393 
    394     return digitSum;
    395 }
    396 
    397 std::vector<int> EulerUtility::intersect(std::vector<int>& a, std::vector<int>& b)
    398 {
    399     std::vector<int> v(a.size() + b.size());
    400     v.resize(std::set_intersection(a.begin(), a.end(), b.begin(), b.end(), v.begin()) - v.begin());
    401     return v;
    402 }
    403 
    404 std::vector<int> EulerUtility::getFigurates(int sides, int floor, int ceiling)
    405 {
    406     std::vector<int> figurates;
    407 
    408     if (sides < 3)
    409         return figurates;
    410 
    411     for (int i = 0; i < ceiling; ++i)
    412     {
    413         int figurate = (sides & 1) ? (i * ((i * (sides - 2)) + 4 - sides)) / 2 : i * ((((sides / 2) - 1) * i) - ((sides / 2) - 2));
    414 
    415         if (figurate >= floor && figurate < ceiling)
    416             figurates.push_back(figurate);
    417 
    418         if (figurate > ceiling)
    419             return figurates;
    420     }
    421 
    422     return figurates;
    423 }
    424 
    425 llui EulerUtility::gcd(llui a, llui b)
    426 {
    427     while (b != 0)
    428     {
    429        llui t = b; 
    430        b = a % b; 
    431        a = t; 
    432     }
    433     return a;
    434 }
    435 
    436 llui EulerUtility::phi(int n, std::vector<int> &primes, std::vector<int> &primesIndexed)
    437 {
    438     // Base case
    439     if (n < 2)
    440         return 0;
    441 
    442     // Lehmer's conjecture
    443     if (primesIndexed[n] != -1)
    444         return n - 1;
    445 
    446     // Even number?
    447     if ((n & 1) == 0)
    448     {
    449         int m = n >> 1;
    450         return !(m & 1) ? EulerUtility::phi(m, primes, primesIndexed) << 1 : EulerUtility::phi(m, primes, primesIndexed);
    451     }
    452 
    453     // For all primes ...
    454     for (std::vector<int>::iterator p = primes.begin(); p != primes.end() && *p <= n; ++p)
    455     {
    456         int m = *p;
    457         if (n % m) continue;
    458 
    459         // phi is multiplicative
    460         int o = n / m;
    461         int d = EulerUtility::gcd(m, o);
    462         return (d == 1) ? EulerUtility::phi(m, primes, primesIndexed) * EulerUtility::phi(o, primes, primesIndexed) : EulerUtility::phi(m, primes, primesIndexed) * EulerUtility::phi(o, primes, primesIndexed) * d / EulerUtility::phi(d, primes, primesIndexed);
    463     }
    464 
    465     return 0;
    466 }