Project Euler 92: count sum-squared-digits chains that reach 89

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
3
down vote

favorite
1













A number chain is created by continuously adding the square of the digits in a number to form a new number until it has been seen before.



For example:



44 → 32 → 13 → 10 → 1 → 1



85 → 89 → 145 → 42 → 20 → 4 → 16 → 37 → 58 → 89



Therefore any chain that arrives at 1 or 89 will become stuck in an endless loop. What is most amazing is that EVERY starting number will eventually arrive at 1 or 89.



How many starting numbers below ten million will arrive at 89?




My solution doesn't finish in under a minute. I'm already caching the results of arrivesAt89, including all permutations. Any help is welcomed.



#include<iostream>
#include<vector>
#include<unordered_map>
#include<algorithm>

int sumOfDigitsSquared(int n)
auto digits = std::to_string(n);
int sum = 0;

for (auto c : digits)
sum = (c - '0') * (c - '0');


return sum;


std::vector<int> permutations(int n)
auto digits = std::to_string(n);
std::vector<int> res;
res.push_back(n);

do
res.push_back(stoi(digits));
while (std::next_permutation(digits.begin(), digits.end()));

return res;


bool arrivesAt89(int n)
static auto cache = std::unordered_map<int,bool>();

int m = n;
while (m != 1)
if(cache.find(m) != cache.end())
return cache.find(m)->second;

if (m == 89)
auto perms = permutations(m);
for (auto p : perms)
cache.insert(p, true);

return true;

m = sumOfDigitsSquared(m);


auto perms = permutations(n);
for (auto p : perms)
cache.insert(p, false);

return false;


int main()
int numberOf89s = 0;

for (int i = 1; i< 10000000; i++)
if (arrivesAt89(i)) numberOf89s++;


std::cout << numberOf89s << std::endl;










share|improve this question



















  • 2




    Although I've answered it now... This code simply doesn't work. It will quickly enter an infinite loop. Code that doesn't work is off-topic for codereview, and on-topic for stackoverflow.
    – user673679
    Dec 9 at 10:46










  • As an aside, it would be more logical to use the smallest number in the circle as the canonical example, rather than the second-largest. But that's for Project Euler themselves.
    – Deduplicator
    Dec 9 at 23:11











  • Project Euler asks people not to share solution code for obvious reasons.
    – Micha Wiedenmann
    Dec 9 at 23:26






  • 5




    @MichaWiedenmann Consensus is that the goal of this site (code review) is more important than PE's request to keep solutions secret (which has obviously been ignored many times over on other sites including personal blogs, so the existence of solutions on SE isn't going to have any great effect).
    – Bob
    Dec 10 at 0:06










  • @user673679 Problem statements without MCVE are not often on-topic for Stack Overflow, so please doublecheck that.
    – Mast
    Dec 10 at 8:41














up vote
3
down vote

favorite
1













A number chain is created by continuously adding the square of the digits in a number to form a new number until it has been seen before.



For example:



44 → 32 → 13 → 10 → 1 → 1



85 → 89 → 145 → 42 → 20 → 4 → 16 → 37 → 58 → 89



Therefore any chain that arrives at 1 or 89 will become stuck in an endless loop. What is most amazing is that EVERY starting number will eventually arrive at 1 or 89.



How many starting numbers below ten million will arrive at 89?




My solution doesn't finish in under a minute. I'm already caching the results of arrivesAt89, including all permutations. Any help is welcomed.



#include<iostream>
#include<vector>
#include<unordered_map>
#include<algorithm>

int sumOfDigitsSquared(int n)
auto digits = std::to_string(n);
int sum = 0;

for (auto c : digits)
sum = (c - '0') * (c - '0');


return sum;


std::vector<int> permutations(int n)
auto digits = std::to_string(n);
std::vector<int> res;
res.push_back(n);

do
res.push_back(stoi(digits));
while (std::next_permutation(digits.begin(), digits.end()));

return res;


bool arrivesAt89(int n)
static auto cache = std::unordered_map<int,bool>();

int m = n;
while (m != 1)
if(cache.find(m) != cache.end())
return cache.find(m)->second;

if (m == 89)
auto perms = permutations(m);
for (auto p : perms)
cache.insert(p, true);

return true;

m = sumOfDigitsSquared(m);


auto perms = permutations(n);
for (auto p : perms)
cache.insert(p, false);

return false;


int main()
int numberOf89s = 0;

for (int i = 1; i< 10000000; i++)
if (arrivesAt89(i)) numberOf89s++;


std::cout << numberOf89s << std::endl;










share|improve this question



















  • 2




    Although I've answered it now... This code simply doesn't work. It will quickly enter an infinite loop. Code that doesn't work is off-topic for codereview, and on-topic for stackoverflow.
    – user673679
    Dec 9 at 10:46










  • As an aside, it would be more logical to use the smallest number in the circle as the canonical example, rather than the second-largest. But that's for Project Euler themselves.
    – Deduplicator
    Dec 9 at 23:11











  • Project Euler asks people not to share solution code for obvious reasons.
    – Micha Wiedenmann
    Dec 9 at 23:26






  • 5




    @MichaWiedenmann Consensus is that the goal of this site (code review) is more important than PE's request to keep solutions secret (which has obviously been ignored many times over on other sites including personal blogs, so the existence of solutions on SE isn't going to have any great effect).
    – Bob
    Dec 10 at 0:06










  • @user673679 Problem statements without MCVE are not often on-topic for Stack Overflow, so please doublecheck that.
    – Mast
    Dec 10 at 8:41












up vote
3
down vote

favorite
1









up vote
3
down vote

favorite
1






1






A number chain is created by continuously adding the square of the digits in a number to form a new number until it has been seen before.



For example:



44 → 32 → 13 → 10 → 1 → 1



85 → 89 → 145 → 42 → 20 → 4 → 16 → 37 → 58 → 89



Therefore any chain that arrives at 1 or 89 will become stuck in an endless loop. What is most amazing is that EVERY starting number will eventually arrive at 1 or 89.



How many starting numbers below ten million will arrive at 89?




My solution doesn't finish in under a minute. I'm already caching the results of arrivesAt89, including all permutations. Any help is welcomed.



#include<iostream>
#include<vector>
#include<unordered_map>
#include<algorithm>

int sumOfDigitsSquared(int n)
auto digits = std::to_string(n);
int sum = 0;

for (auto c : digits)
sum = (c - '0') * (c - '0');


return sum;


std::vector<int> permutations(int n)
auto digits = std::to_string(n);
std::vector<int> res;
res.push_back(n);

do
res.push_back(stoi(digits));
while (std::next_permutation(digits.begin(), digits.end()));

return res;


bool arrivesAt89(int n)
static auto cache = std::unordered_map<int,bool>();

int m = n;
while (m != 1)
if(cache.find(m) != cache.end())
return cache.find(m)->second;

if (m == 89)
auto perms = permutations(m);
for (auto p : perms)
cache.insert(p, true);

return true;

m = sumOfDigitsSquared(m);


auto perms = permutations(n);
for (auto p : perms)
cache.insert(p, false);

return false;


int main()
int numberOf89s = 0;

for (int i = 1; i< 10000000; i++)
if (arrivesAt89(i)) numberOf89s++;


std::cout << numberOf89s << std::endl;










share|improve this question
















A number chain is created by continuously adding the square of the digits in a number to form a new number until it has been seen before.



For example:



44 → 32 → 13 → 10 → 1 → 1



85 → 89 → 145 → 42 → 20 → 4 → 16 → 37 → 58 → 89



Therefore any chain that arrives at 1 or 89 will become stuck in an endless loop. What is most amazing is that EVERY starting number will eventually arrive at 1 or 89.



How many starting numbers below ten million will arrive at 89?




My solution doesn't finish in under a minute. I'm already caching the results of arrivesAt89, including all permutations. Any help is welcomed.



#include<iostream>
#include<vector>
#include<unordered_map>
#include<algorithm>

int sumOfDigitsSquared(int n)
auto digits = std::to_string(n);
int sum = 0;

for (auto c : digits)
sum = (c - '0') * (c - '0');


return sum;


std::vector<int> permutations(int n)
auto digits = std::to_string(n);
std::vector<int> res;
res.push_back(n);

do
res.push_back(stoi(digits));
while (std::next_permutation(digits.begin(), digits.end()));

return res;


bool arrivesAt89(int n)
static auto cache = std::unordered_map<int,bool>();

int m = n;
while (m != 1)
if(cache.find(m) != cache.end())
return cache.find(m)->second;

if (m == 89)
auto perms = permutations(m);
for (auto p : perms)
cache.insert(p, true);

return true;

m = sumOfDigitsSquared(m);


auto perms = permutations(n);
for (auto p : perms)
cache.insert(p, false);

return false;


int main()
int numberOf89s = 0;

for (int i = 1; i< 10000000; i++)
if (arrivesAt89(i)) numberOf89s++;


std::cout << numberOf89s << std::endl;







c++ performance programming-challenge time-limit-exceeded






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Dec 12 at 13:12









Toby Speight

23.3k639111




23.3k639111










asked Dec 9 at 8:12









Philipp Siegmantel

1222




1222







  • 2




    Although I've answered it now... This code simply doesn't work. It will quickly enter an infinite loop. Code that doesn't work is off-topic for codereview, and on-topic for stackoverflow.
    – user673679
    Dec 9 at 10:46










  • As an aside, it would be more logical to use the smallest number in the circle as the canonical example, rather than the second-largest. But that's for Project Euler themselves.
    – Deduplicator
    Dec 9 at 23:11











  • Project Euler asks people not to share solution code for obvious reasons.
    – Micha Wiedenmann
    Dec 9 at 23:26






  • 5




    @MichaWiedenmann Consensus is that the goal of this site (code review) is more important than PE's request to keep solutions secret (which has obviously been ignored many times over on other sites including personal blogs, so the existence of solutions on SE isn't going to have any great effect).
    – Bob
    Dec 10 at 0:06










  • @user673679 Problem statements without MCVE are not often on-topic for Stack Overflow, so please doublecheck that.
    – Mast
    Dec 10 at 8:41












  • 2




    Although I've answered it now... This code simply doesn't work. It will quickly enter an infinite loop. Code that doesn't work is off-topic for codereview, and on-topic for stackoverflow.
    – user673679
    Dec 9 at 10:46










  • As an aside, it would be more logical to use the smallest number in the circle as the canonical example, rather than the second-largest. But that's for Project Euler themselves.
    – Deduplicator
    Dec 9 at 23:11











  • Project Euler asks people not to share solution code for obvious reasons.
    – Micha Wiedenmann
    Dec 9 at 23:26






  • 5




    @MichaWiedenmann Consensus is that the goal of this site (code review) is more important than PE's request to keep solutions secret (which has obviously been ignored many times over on other sites including personal blogs, so the existence of solutions on SE isn't going to have any great effect).
    – Bob
    Dec 10 at 0:06










  • @user673679 Problem statements without MCVE are not often on-topic for Stack Overflow, so please doublecheck that.
    – Mast
    Dec 10 at 8:41







2




2




Although I've answered it now... This code simply doesn't work. It will quickly enter an infinite loop. Code that doesn't work is off-topic for codereview, and on-topic for stackoverflow.
– user673679
Dec 9 at 10:46




Although I've answered it now... This code simply doesn't work. It will quickly enter an infinite loop. Code that doesn't work is off-topic for codereview, and on-topic for stackoverflow.
– user673679
Dec 9 at 10:46












As an aside, it would be more logical to use the smallest number in the circle as the canonical example, rather than the second-largest. But that's for Project Euler themselves.
– Deduplicator
Dec 9 at 23:11





As an aside, it would be more logical to use the smallest number in the circle as the canonical example, rather than the second-largest. But that's for Project Euler themselves.
– Deduplicator
Dec 9 at 23:11













Project Euler asks people not to share solution code for obvious reasons.
– Micha Wiedenmann
Dec 9 at 23:26




Project Euler asks people not to share solution code for obvious reasons.
– Micha Wiedenmann
Dec 9 at 23:26




5




5




@MichaWiedenmann Consensus is that the goal of this site (code review) is more important than PE's request to keep solutions secret (which has obviously been ignored many times over on other sites including personal blogs, so the existence of solutions on SE isn't going to have any great effect).
– Bob
Dec 10 at 0:06




@MichaWiedenmann Consensus is that the goal of this site (code review) is more important than PE's request to keep solutions secret (which has obviously been ignored many times over on other sites including personal blogs, so the existence of solutions on SE isn't going to have any great effect).
– Bob
Dec 10 at 0:06












@user673679 Problem statements without MCVE are not often on-topic for Stack Overflow, so please doublecheck that.
– Mast
Dec 10 at 8:41




@user673679 Problem statements without MCVE are not often on-topic for Stack Overflow, so please doublecheck that.
– Mast
Dec 10 at 8:41










5 Answers
5






active

oldest

votes

















up vote
10
down vote













  • I guess the idea behind using permutations is that any permutation of the same digits will result in the same squared sum. However... in that case, shouldn't we simply calculate the squared sum and cache that?

  • It appears that we're only caching the permutations of the digits at the end of the chain. i.e. we'll only ever end up with 1, 89 and 98 in the map! We should probably be caching all the values in the chain up to the final result.


  • #include <string> for std::to_string.

  • Converting to and from std::string is probably quite slow. We can use simple integer arithmetic to extract the individual digits.

  • The implementation of sumOfDigitsSquared is clearly incorrect with basic testing.





share|improve this answer






















  • The % can also be slow. Don't assume your method is faster without measuring. (I don't say it's slower, but you have to measure before making assumptions).
    – Calak
    Dec 9 at 12:14










  • "The implementation of sumOfDigitsSquared is clearly incorrect with basic testing" can you explain why it's incorrect?
    – Calak
    Dec 9 at 12:15






  • 2




    @Calak only the last iteration of the loop matters, it continuously overwrites sum. += is probably needed.
    – Wes Toleman
    Dec 9 at 14:48







  • 1




    @WesTolemanWe I know, but I asked him to try to be more precise about why it doesn't work. Just telling "it's broken" without explaining why is almost pointless.
    – Calak
    Dec 9 at 15:32






  • 1




    @Calak I think it's much better for OP to find the exact problem themselves. It's not hard to find, and doing so helps more with the actual issue (OP needs to learn to debug and test code). The point of that statement is "do basic testing", not "it's broken".
    – user673679
    Dec 9 at 16:33

















up vote
3
down vote













Obviously, the algorithm provided will set up a number of equivalence classes of numbers containing the same ciphers. E. g. 1012, 1210, and all other permutations of are equivalent.



So you might want to sort the numbers by their digits (skipping all zeros), so you'd only have to store 112 for above numbers, or the other way round, only generate the sorted numbers by some appropriate algorithm.



Finally, you can easily generate the number of permutations from these numbers. Example above:



00 000 112


There are 8! but we need to divide by the number of equivalent permutations (due to the five zeros and the two ones), so we get:



8! / 5! / 2!


A mentioned number generator might look like this one:



std::vector<unsigned int> current(1, 2, 3, 4, 5, 6, 7, 8, 9 );
std::vector<unsigned int> previous;

for(unsigned int i = 0; i < 7; ++i)

using std::swap;
for(auto n : current)
std::cout << n << ' ';
std::cout << std::endl;
swap(current, previous);
current.clear();
for(auto n : previous)

for(unsigned int m = 1; m <= n % 10; ++m)

current.push_back(n * 10 + m);





producing all sorted numbers up to 7 digits (OK, within numbers, sorting order is invers, but that's not of relevance...).






share|improve this answer





























    up vote
    3
    down vote













    Plenty of good answers have been given I'll just point out that 10 million is actually not a lot.



    The square sum of digits of 9999999 is 7*81=567 and this is the largest sum you can get. So to determine if any up to 7 digit number ends up as 1 or 89 cannot require more than 567 iterations of computing the sum of squared digits.



    Meaning that brute force 567*10M=5.67 G iterations of computing sum of digits squared will solve it. Sum of digits squared using the trivial integer division approach is 7 divisions with remainder, 6 additions and 7 multiples, plus loop overhead call it 30 instructions, so in total you'd need 5.67*30~=16G instructions.



    For a typical desktop computer with 4 GHz one core turbo and IPC of 2 (which is pessimistic for modern x86 CPUs) that amounts to 8 G instructions per second, which means brute force should take around two seconds if my math isn't completely of the charts wrong.



    So you can do a bunch of clever stuff but it won't save you more than two seconds of CPU time over just brute forcing it. And you can do much worse than brute force as OPs solution doesn't complete after a whole minute by computing ineffective sums, allocating a bunch of memory left right and center, generating permutations and what not.



    Edit: To prove my point:



    I implemented the brute force soloution:



    pe.cpp



    #include <iostream>

    int ssd(int n)
    int ans = 0;
    while(n)
    int d = n%10;
    n = n/10;
    ans += d*d;

    return ans;


    int main(int, char**)
    int n89 = 0;
    for(int n = 2; n < 10000000; n++)
    int s = ssd(n);
    while(s != 1 && s != 89)
    s = ssd(s);

    if(s==89)
    n89++;


    std::cout<<n89<<std::endl;



    And ran it, producing the correct solution in under half a second:



    $ g++ -O3 pe.cpp -o pe && time ./pe
    8581146

    real 0m0.423s
    user 0m0.423s
    sys 0m0.000s


    On my machine:



    $ cat /proc/cpuinfo | grep "model name" | tail -n 1
    model name : Intel(R) Core(TM) i7-8700K CPU @ 3.70GHz





    share|improve this answer






















    • Completing a challenge from the Euler Project should ask for more than mere brute force. The criterium stated on the home page is that the algorithm shouldn't take more than one minute on an average machine to complete. Your machine isn't what I'd call average, and using C++ over other slower languages is already a boost. Even if the original poster devised a rather clumsy solution, I believe he's right in trying to beat brute force.
      – papagaga
      Dec 11 at 13:02










    • I disagree, some of the early questions can be solved with just pen and paper. While my machine is quite strong, it also computed the solution in less than 0.5 s on one core. So a machine with 1/120 the single core performance of mine should still make the 1 minute mark. So even something that has only a fifth of the performance of a VIA Eden 1 GHz low power CPU should still be able to compute it in under a minute... I bet even a Pentium 200 would make it under one minute (cpubenchmark.net/singleThread.html). I think that's below average, yes?
      – Emily L.
      Dec 11 at 22:30






    • 1




      @papagaga what I'm trying to say is that sometimes the brute force solution is the best one, or at least good enough. For example shaker sort (two sided bubble sort) of faster than quicksort on almost sorted arrays (codereview.stackexchange.com/a/159974/36120). Knowing when you can and should use an "inefficient" solution is an important skill for a software engineer.
      – Emily L.
      Dec 11 at 22:38










    • @EmiliL: ... I'm not sure how it happened, but I was mixing up minutes and seconds. You're absolutely right.
      – papagaga
      Dec 12 at 7:52

















    up vote
    3
    down vote













    int sumOfDigitsSquared(int n) 
    auto digits = std::to_string(n);
    int sum = 0;

    for (auto c : digits)
    sum += (c - '0') * (c - '0'); // I corrected the = into +=


    return sum;



    Conversions come with a performance hit, especially when the conversion implies memory allocation and copy, as here with std::to_string. It would make perfect sense if you had some use for the string, but you don't, since you return another int. And the math behind it is really basic:



    constexpr int sum_of_squared_digits(int n) 
    int res = 0;
    while (n)
    const int digit = n % 10;
    res += digit * digit;
    n /= 10;

    return res;



    I've marked it constexpr, only to hint that the whole algorithm could be performed at compile-time, but it wouldn't really be fair, so it won't.



    bool arrivesAt89(int n) 
    static auto cache = std::unordered_map<int,bool>();


    unordered_map might not be necessary in this case. A simple array would suffice, with 0 meaning unexplored, 1 ending with 1 and 89 ending with 89: it's even faster and all the memory allocation is done upfront.



     int m = n;
    while (m != 1)
    if(cache.find(m) != cache.end())
    return cache.find(m)->second;

    if (m == 89)
    auto perms = permutations(m);
    for (auto p : perms)
    cache.insert(p, true);

    return true;

    m = sumOfDigitsSquared(m);


    Here is I think the main weakness of your algorithm: you only cache the result for the number n and its permutations; all intermediary values are ignored, although they belong on the same path as n and would populate the map much faster.



     

    auto perms = permutations(n);
    for (auto p : perms)
    cache.insert(p, false);

    return false;



    Computing the permutations come with another heavy conversion, with memory allocation and copy (std::to_string) and a std::vector you won't use beyond feeding it to the static std::unordered_map inside your master function.



    std::vector<int> permutations(int n) 
    auto digits = std::to_string(n);
    std::vector<int> res;
    res.push_back(n);

    do
    res.push_back(stoi(digits));
    while (std::next_permutation(digits.begin(), digits.end()));


    Besides, it won't give you every permutation: if you want to go through all permutations with std::next_permutation, you need to start with a sorted std::string.



     return res;



    Anyway, I don't think that permutations are the best way of testing the numbers equivalence: you don't need it if you keep track of intermediary values, because permutations will result in the same squared digits' sum.



    Here what I'd find correctly optimized:



    auto precompute_results(int n) 
    std::vector<int> results(n, 0);
    // a vector instead of a map,
    // elements can be:
    // 0 = unexplored, 1 = ending in 1, 89 = ending in 89
    // n = on the same path as n
    for (int i = 1; i < n; ++i)
    auto cur = results[i] ? results[i] : i;
    while (true)
    results[i] = cur;

    return results;






    share|improve this answer





























      up vote
      1
      down vote













      Sometimes it's good to remember the KISS principle.



      With this in mind, first the squares of each digit is constant therefore a constant int to store those values will eliminate constantly multiplying them.



      Integer math is much faster than string conversions.



      One solution taking this in to account could look like this:



      const int squares = 0,1,4,9,16,25,36,49,64,81 ;
      bool IsSquareSum89(int num)

      int sum = 0;
      while (num != 89 && num != 1)

      sum = 0;
      while (num > 0)

      int digit = num % 10;
      sum += squares[digit];
      num /= 10;

      num = sum;

      return num == 89;

      int GetAnswer(int target)

      int answer = 0;
      for (int i = target - 1; i > 0; --i)

      if (IsSquareSum89(i))

      ++answer;


      return answer;



      On my machine this finds the answer in about 2 seconds.






      share|improve this answer




















      • So you optimize out a measly integer multiplication, that is right next to a division... that is wasted optimization effort. Plus: to fetch a value from an array requires an integer multiplication!
        – Cris Luengo
        Dec 11 at 1:43











      • @CrisLuengo "to fetch a value from an array requires an integer multiplication" - Not always. For byte arrays, no operation is required. For an int array like this, rather than multiplication, you shift the index left by two, which is pretty cheap.
        – Reinderien
        Dec 11 at 1:50










      • I'm pretty sure that the array access is more expensive than a multiplication: there is the memory access (maybe 100 × longer than a multiplication) and the offset calculation
        – papagaga
        Dec 11 at 8:02










      • @papagaga - when I compare this code with EmilyL's , which uses the same basic algorithm, this code is slightly faster. The difference is probably close enough to say that they're even.
        – tinstaafl
        Dec 11 at 12:17










      • You're right: in this case, since your array is small enough to hold in a cache line, access won't cost more than a multiplication -but still not much less either, whereas it makes the program a little more complicated.
        – papagaga
        Dec 11 at 13:06










      Your Answer





      StackExchange.ifUsing("editor", function ()
      return StackExchange.using("mathjaxEditing", function ()
      StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
      StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
      );
      );
      , "mathjax-editing");

      StackExchange.ifUsing("editor", function ()
      StackExchange.using("externalEditor", function ()
      StackExchange.using("snippets", function ()
      StackExchange.snippets.init();
      );
      );
      , "code-snippets");

      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "196"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: false,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: null,
      bindNavPrevention: true,
      postfix: "",
      imageUploader:
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      ,
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );













      draft saved

      draft discarded


















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209303%2fproject-euler-92-count-sum-squared-digits-chains-that-reach-89%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown

























      5 Answers
      5






      active

      oldest

      votes








      5 Answers
      5






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes








      up vote
      10
      down vote













      • I guess the idea behind using permutations is that any permutation of the same digits will result in the same squared sum. However... in that case, shouldn't we simply calculate the squared sum and cache that?

      • It appears that we're only caching the permutations of the digits at the end of the chain. i.e. we'll only ever end up with 1, 89 and 98 in the map! We should probably be caching all the values in the chain up to the final result.


      • #include <string> for std::to_string.

      • Converting to and from std::string is probably quite slow. We can use simple integer arithmetic to extract the individual digits.

      • The implementation of sumOfDigitsSquared is clearly incorrect with basic testing.





      share|improve this answer






















      • The % can also be slow. Don't assume your method is faster without measuring. (I don't say it's slower, but you have to measure before making assumptions).
        – Calak
        Dec 9 at 12:14










      • "The implementation of sumOfDigitsSquared is clearly incorrect with basic testing" can you explain why it's incorrect?
        – Calak
        Dec 9 at 12:15






      • 2




        @Calak only the last iteration of the loop matters, it continuously overwrites sum. += is probably needed.
        – Wes Toleman
        Dec 9 at 14:48







      • 1




        @WesTolemanWe I know, but I asked him to try to be more precise about why it doesn't work. Just telling "it's broken" without explaining why is almost pointless.
        – Calak
        Dec 9 at 15:32






      • 1




        @Calak I think it's much better for OP to find the exact problem themselves. It's not hard to find, and doing so helps more with the actual issue (OP needs to learn to debug and test code). The point of that statement is "do basic testing", not "it's broken".
        – user673679
        Dec 9 at 16:33














      up vote
      10
      down vote













      • I guess the idea behind using permutations is that any permutation of the same digits will result in the same squared sum. However... in that case, shouldn't we simply calculate the squared sum and cache that?

      • It appears that we're only caching the permutations of the digits at the end of the chain. i.e. we'll only ever end up with 1, 89 and 98 in the map! We should probably be caching all the values in the chain up to the final result.


      • #include <string> for std::to_string.

      • Converting to and from std::string is probably quite slow. We can use simple integer arithmetic to extract the individual digits.

      • The implementation of sumOfDigitsSquared is clearly incorrect with basic testing.





      share|improve this answer






















      • The % can also be slow. Don't assume your method is faster without measuring. (I don't say it's slower, but you have to measure before making assumptions).
        – Calak
        Dec 9 at 12:14










      • "The implementation of sumOfDigitsSquared is clearly incorrect with basic testing" can you explain why it's incorrect?
        – Calak
        Dec 9 at 12:15






      • 2




        @Calak only the last iteration of the loop matters, it continuously overwrites sum. += is probably needed.
        – Wes Toleman
        Dec 9 at 14:48







      • 1




        @WesTolemanWe I know, but I asked him to try to be more precise about why it doesn't work. Just telling "it's broken" without explaining why is almost pointless.
        – Calak
        Dec 9 at 15:32






      • 1




        @Calak I think it's much better for OP to find the exact problem themselves. It's not hard to find, and doing so helps more with the actual issue (OP needs to learn to debug and test code). The point of that statement is "do basic testing", not "it's broken".
        – user673679
        Dec 9 at 16:33












      up vote
      10
      down vote










      up vote
      10
      down vote









      • I guess the idea behind using permutations is that any permutation of the same digits will result in the same squared sum. However... in that case, shouldn't we simply calculate the squared sum and cache that?

      • It appears that we're only caching the permutations of the digits at the end of the chain. i.e. we'll only ever end up with 1, 89 and 98 in the map! We should probably be caching all the values in the chain up to the final result.


      • #include <string> for std::to_string.

      • Converting to and from std::string is probably quite slow. We can use simple integer arithmetic to extract the individual digits.

      • The implementation of sumOfDigitsSquared is clearly incorrect with basic testing.





      share|improve this answer














      • I guess the idea behind using permutations is that any permutation of the same digits will result in the same squared sum. However... in that case, shouldn't we simply calculate the squared sum and cache that?

      • It appears that we're only caching the permutations of the digits at the end of the chain. i.e. we'll only ever end up with 1, 89 and 98 in the map! We should probably be caching all the values in the chain up to the final result.


      • #include <string> for std::to_string.

      • Converting to and from std::string is probably quite slow. We can use simple integer arithmetic to extract the individual digits.

      • The implementation of sumOfDigitsSquared is clearly incorrect with basic testing.






      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Dec 9 at 16:19

























      answered Dec 9 at 10:44









      user673679

      2,184725




      2,184725











      • The % can also be slow. Don't assume your method is faster without measuring. (I don't say it's slower, but you have to measure before making assumptions).
        – Calak
        Dec 9 at 12:14










      • "The implementation of sumOfDigitsSquared is clearly incorrect with basic testing" can you explain why it's incorrect?
        – Calak
        Dec 9 at 12:15






      • 2




        @Calak only the last iteration of the loop matters, it continuously overwrites sum. += is probably needed.
        – Wes Toleman
        Dec 9 at 14:48







      • 1




        @WesTolemanWe I know, but I asked him to try to be more precise about why it doesn't work. Just telling "it's broken" without explaining why is almost pointless.
        – Calak
        Dec 9 at 15:32






      • 1




        @Calak I think it's much better for OP to find the exact problem themselves. It's not hard to find, and doing so helps more with the actual issue (OP needs to learn to debug and test code). The point of that statement is "do basic testing", not "it's broken".
        – user673679
        Dec 9 at 16:33
















      • The % can also be slow. Don't assume your method is faster without measuring. (I don't say it's slower, but you have to measure before making assumptions).
        – Calak
        Dec 9 at 12:14










      • "The implementation of sumOfDigitsSquared is clearly incorrect with basic testing" can you explain why it's incorrect?
        – Calak
        Dec 9 at 12:15






      • 2




        @Calak only the last iteration of the loop matters, it continuously overwrites sum. += is probably needed.
        – Wes Toleman
        Dec 9 at 14:48







      • 1




        @WesTolemanWe I know, but I asked him to try to be more precise about why it doesn't work. Just telling "it's broken" without explaining why is almost pointless.
        – Calak
        Dec 9 at 15:32






      • 1




        @Calak I think it's much better for OP to find the exact problem themselves. It's not hard to find, and doing so helps more with the actual issue (OP needs to learn to debug and test code). The point of that statement is "do basic testing", not "it's broken".
        – user673679
        Dec 9 at 16:33















      The % can also be slow. Don't assume your method is faster without measuring. (I don't say it's slower, but you have to measure before making assumptions).
      – Calak
      Dec 9 at 12:14




      The % can also be slow. Don't assume your method is faster without measuring. (I don't say it's slower, but you have to measure before making assumptions).
      – Calak
      Dec 9 at 12:14












      "The implementation of sumOfDigitsSquared is clearly incorrect with basic testing" can you explain why it's incorrect?
      – Calak
      Dec 9 at 12:15




      "The implementation of sumOfDigitsSquared is clearly incorrect with basic testing" can you explain why it's incorrect?
      – Calak
      Dec 9 at 12:15




      2




      2




      @Calak only the last iteration of the loop matters, it continuously overwrites sum. += is probably needed.
      – Wes Toleman
      Dec 9 at 14:48





      @Calak only the last iteration of the loop matters, it continuously overwrites sum. += is probably needed.
      – Wes Toleman
      Dec 9 at 14:48





      1




      1




      @WesTolemanWe I know, but I asked him to try to be more precise about why it doesn't work. Just telling "it's broken" without explaining why is almost pointless.
      – Calak
      Dec 9 at 15:32




      @WesTolemanWe I know, but I asked him to try to be more precise about why it doesn't work. Just telling "it's broken" without explaining why is almost pointless.
      – Calak
      Dec 9 at 15:32




      1




      1




      @Calak I think it's much better for OP to find the exact problem themselves. It's not hard to find, and doing so helps more with the actual issue (OP needs to learn to debug and test code). The point of that statement is "do basic testing", not "it's broken".
      – user673679
      Dec 9 at 16:33




      @Calak I think it's much better for OP to find the exact problem themselves. It's not hard to find, and doing so helps more with the actual issue (OP needs to learn to debug and test code). The point of that statement is "do basic testing", not "it's broken".
      – user673679
      Dec 9 at 16:33












      up vote
      3
      down vote













      Obviously, the algorithm provided will set up a number of equivalence classes of numbers containing the same ciphers. E. g. 1012, 1210, and all other permutations of are equivalent.



      So you might want to sort the numbers by their digits (skipping all zeros), so you'd only have to store 112 for above numbers, or the other way round, only generate the sorted numbers by some appropriate algorithm.



      Finally, you can easily generate the number of permutations from these numbers. Example above:



      00 000 112


      There are 8! but we need to divide by the number of equivalent permutations (due to the five zeros and the two ones), so we get:



      8! / 5! / 2!


      A mentioned number generator might look like this one:



      std::vector<unsigned int> current(1, 2, 3, 4, 5, 6, 7, 8, 9 );
      std::vector<unsigned int> previous;

      for(unsigned int i = 0; i < 7; ++i)

      using std::swap;
      for(auto n : current)
      std::cout << n << ' ';
      std::cout << std::endl;
      swap(current, previous);
      current.clear();
      for(auto n : previous)

      for(unsigned int m = 1; m <= n % 10; ++m)

      current.push_back(n * 10 + m);





      producing all sorted numbers up to 7 digits (OK, within numbers, sorting order is invers, but that's not of relevance...).






      share|improve this answer


























        up vote
        3
        down vote













        Obviously, the algorithm provided will set up a number of equivalence classes of numbers containing the same ciphers. E. g. 1012, 1210, and all other permutations of are equivalent.



        So you might want to sort the numbers by their digits (skipping all zeros), so you'd only have to store 112 for above numbers, or the other way round, only generate the sorted numbers by some appropriate algorithm.



        Finally, you can easily generate the number of permutations from these numbers. Example above:



        00 000 112


        There are 8! but we need to divide by the number of equivalent permutations (due to the five zeros and the two ones), so we get:



        8! / 5! / 2!


        A mentioned number generator might look like this one:



        std::vector<unsigned int> current(1, 2, 3, 4, 5, 6, 7, 8, 9 );
        std::vector<unsigned int> previous;

        for(unsigned int i = 0; i < 7; ++i)

        using std::swap;
        for(auto n : current)
        std::cout << n << ' ';
        std::cout << std::endl;
        swap(current, previous);
        current.clear();
        for(auto n : previous)

        for(unsigned int m = 1; m <= n % 10; ++m)

        current.push_back(n * 10 + m);





        producing all sorted numbers up to 7 digits (OK, within numbers, sorting order is invers, but that's not of relevance...).






        share|improve this answer
























          up vote
          3
          down vote










          up vote
          3
          down vote









          Obviously, the algorithm provided will set up a number of equivalence classes of numbers containing the same ciphers. E. g. 1012, 1210, and all other permutations of are equivalent.



          So you might want to sort the numbers by their digits (skipping all zeros), so you'd only have to store 112 for above numbers, or the other way round, only generate the sorted numbers by some appropriate algorithm.



          Finally, you can easily generate the number of permutations from these numbers. Example above:



          00 000 112


          There are 8! but we need to divide by the number of equivalent permutations (due to the five zeros and the two ones), so we get:



          8! / 5! / 2!


          A mentioned number generator might look like this one:



          std::vector<unsigned int> current(1, 2, 3, 4, 5, 6, 7, 8, 9 );
          std::vector<unsigned int> previous;

          for(unsigned int i = 0; i < 7; ++i)

          using std::swap;
          for(auto n : current)
          std::cout << n << ' ';
          std::cout << std::endl;
          swap(current, previous);
          current.clear();
          for(auto n : previous)

          for(unsigned int m = 1; m <= n % 10; ++m)

          current.push_back(n * 10 + m);





          producing all sorted numbers up to 7 digits (OK, within numbers, sorting order is invers, but that's not of relevance...).






          share|improve this answer














          Obviously, the algorithm provided will set up a number of equivalence classes of numbers containing the same ciphers. E. g. 1012, 1210, and all other permutations of are equivalent.



          So you might want to sort the numbers by their digits (skipping all zeros), so you'd only have to store 112 for above numbers, or the other way round, only generate the sorted numbers by some appropriate algorithm.



          Finally, you can easily generate the number of permutations from these numbers. Example above:



          00 000 112


          There are 8! but we need to divide by the number of equivalent permutations (due to the five zeros and the two ones), so we get:



          8! / 5! / 2!


          A mentioned number generator might look like this one:



          std::vector<unsigned int> current(1, 2, 3, 4, 5, 6, 7, 8, 9 );
          std::vector<unsigned int> previous;

          for(unsigned int i = 0; i < 7; ++i)

          using std::swap;
          for(auto n : current)
          std::cout << n << ' ';
          std::cout << std::endl;
          swap(current, previous);
          current.clear();
          for(auto n : previous)

          for(unsigned int m = 1; m <= n % 10; ++m)

          current.push_back(n * 10 + m);





          producing all sorted numbers up to 7 digits (OK, within numbers, sorting order is invers, but that's not of relevance...).







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Dec 9 at 17:00









          user1118321

          10.7k11145




          10.7k11145










          answered Dec 9 at 10:22









          Aconcagua

          3116




          3116




















              up vote
              3
              down vote













              Plenty of good answers have been given I'll just point out that 10 million is actually not a lot.



              The square sum of digits of 9999999 is 7*81=567 and this is the largest sum you can get. So to determine if any up to 7 digit number ends up as 1 or 89 cannot require more than 567 iterations of computing the sum of squared digits.



              Meaning that brute force 567*10M=5.67 G iterations of computing sum of digits squared will solve it. Sum of digits squared using the trivial integer division approach is 7 divisions with remainder, 6 additions and 7 multiples, plus loop overhead call it 30 instructions, so in total you'd need 5.67*30~=16G instructions.



              For a typical desktop computer with 4 GHz one core turbo and IPC of 2 (which is pessimistic for modern x86 CPUs) that amounts to 8 G instructions per second, which means brute force should take around two seconds if my math isn't completely of the charts wrong.



              So you can do a bunch of clever stuff but it won't save you more than two seconds of CPU time over just brute forcing it. And you can do much worse than brute force as OPs solution doesn't complete after a whole minute by computing ineffective sums, allocating a bunch of memory left right and center, generating permutations and what not.



              Edit: To prove my point:



              I implemented the brute force soloution:



              pe.cpp



              #include <iostream>

              int ssd(int n)
              int ans = 0;
              while(n)
              int d = n%10;
              n = n/10;
              ans += d*d;

              return ans;


              int main(int, char**)
              int n89 = 0;
              for(int n = 2; n < 10000000; n++)
              int s = ssd(n);
              while(s != 1 && s != 89)
              s = ssd(s);

              if(s==89)
              n89++;


              std::cout<<n89<<std::endl;



              And ran it, producing the correct solution in under half a second:



              $ g++ -O3 pe.cpp -o pe && time ./pe
              8581146

              real 0m0.423s
              user 0m0.423s
              sys 0m0.000s


              On my machine:



              $ cat /proc/cpuinfo | grep "model name" | tail -n 1
              model name : Intel(R) Core(TM) i7-8700K CPU @ 3.70GHz





              share|improve this answer






















              • Completing a challenge from the Euler Project should ask for more than mere brute force. The criterium stated on the home page is that the algorithm shouldn't take more than one minute on an average machine to complete. Your machine isn't what I'd call average, and using C++ over other slower languages is already a boost. Even if the original poster devised a rather clumsy solution, I believe he's right in trying to beat brute force.
                – papagaga
                Dec 11 at 13:02










              • I disagree, some of the early questions can be solved with just pen and paper. While my machine is quite strong, it also computed the solution in less than 0.5 s on one core. So a machine with 1/120 the single core performance of mine should still make the 1 minute mark. So even something that has only a fifth of the performance of a VIA Eden 1 GHz low power CPU should still be able to compute it in under a minute... I bet even a Pentium 200 would make it under one minute (cpubenchmark.net/singleThread.html). I think that's below average, yes?
                – Emily L.
                Dec 11 at 22:30






              • 1




                @papagaga what I'm trying to say is that sometimes the brute force solution is the best one, or at least good enough. For example shaker sort (two sided bubble sort) of faster than quicksort on almost sorted arrays (codereview.stackexchange.com/a/159974/36120). Knowing when you can and should use an "inefficient" solution is an important skill for a software engineer.
                – Emily L.
                Dec 11 at 22:38










              • @EmiliL: ... I'm not sure how it happened, but I was mixing up minutes and seconds. You're absolutely right.
                – papagaga
                Dec 12 at 7:52














              up vote
              3
              down vote













              Plenty of good answers have been given I'll just point out that 10 million is actually not a lot.



              The square sum of digits of 9999999 is 7*81=567 and this is the largest sum you can get. So to determine if any up to 7 digit number ends up as 1 or 89 cannot require more than 567 iterations of computing the sum of squared digits.



              Meaning that brute force 567*10M=5.67 G iterations of computing sum of digits squared will solve it. Sum of digits squared using the trivial integer division approach is 7 divisions with remainder, 6 additions and 7 multiples, plus loop overhead call it 30 instructions, so in total you'd need 5.67*30~=16G instructions.



              For a typical desktop computer with 4 GHz one core turbo and IPC of 2 (which is pessimistic for modern x86 CPUs) that amounts to 8 G instructions per second, which means brute force should take around two seconds if my math isn't completely of the charts wrong.



              So you can do a bunch of clever stuff but it won't save you more than two seconds of CPU time over just brute forcing it. And you can do much worse than brute force as OPs solution doesn't complete after a whole minute by computing ineffective sums, allocating a bunch of memory left right and center, generating permutations and what not.



              Edit: To prove my point:



              I implemented the brute force soloution:



              pe.cpp



              #include <iostream>

              int ssd(int n)
              int ans = 0;
              while(n)
              int d = n%10;
              n = n/10;
              ans += d*d;

              return ans;


              int main(int, char**)
              int n89 = 0;
              for(int n = 2; n < 10000000; n++)
              int s = ssd(n);
              while(s != 1 && s != 89)
              s = ssd(s);

              if(s==89)
              n89++;


              std::cout<<n89<<std::endl;



              And ran it, producing the correct solution in under half a second:



              $ g++ -O3 pe.cpp -o pe && time ./pe
              8581146

              real 0m0.423s
              user 0m0.423s
              sys 0m0.000s


              On my machine:



              $ cat /proc/cpuinfo | grep "model name" | tail -n 1
              model name : Intel(R) Core(TM) i7-8700K CPU @ 3.70GHz





              share|improve this answer






















              • Completing a challenge from the Euler Project should ask for more than mere brute force. The criterium stated on the home page is that the algorithm shouldn't take more than one minute on an average machine to complete. Your machine isn't what I'd call average, and using C++ over other slower languages is already a boost. Even if the original poster devised a rather clumsy solution, I believe he's right in trying to beat brute force.
                – papagaga
                Dec 11 at 13:02










              • I disagree, some of the early questions can be solved with just pen and paper. While my machine is quite strong, it also computed the solution in less than 0.5 s on one core. So a machine with 1/120 the single core performance of mine should still make the 1 minute mark. So even something that has only a fifth of the performance of a VIA Eden 1 GHz low power CPU should still be able to compute it in under a minute... I bet even a Pentium 200 would make it under one minute (cpubenchmark.net/singleThread.html). I think that's below average, yes?
                – Emily L.
                Dec 11 at 22:30






              • 1




                @papagaga what I'm trying to say is that sometimes the brute force solution is the best one, or at least good enough. For example shaker sort (two sided bubble sort) of faster than quicksort on almost sorted arrays (codereview.stackexchange.com/a/159974/36120). Knowing when you can and should use an "inefficient" solution is an important skill for a software engineer.
                – Emily L.
                Dec 11 at 22:38










              • @EmiliL: ... I'm not sure how it happened, but I was mixing up minutes and seconds. You're absolutely right.
                – papagaga
                Dec 12 at 7:52












              up vote
              3
              down vote










              up vote
              3
              down vote









              Plenty of good answers have been given I'll just point out that 10 million is actually not a lot.



              The square sum of digits of 9999999 is 7*81=567 and this is the largest sum you can get. So to determine if any up to 7 digit number ends up as 1 or 89 cannot require more than 567 iterations of computing the sum of squared digits.



              Meaning that brute force 567*10M=5.67 G iterations of computing sum of digits squared will solve it. Sum of digits squared using the trivial integer division approach is 7 divisions with remainder, 6 additions and 7 multiples, plus loop overhead call it 30 instructions, so in total you'd need 5.67*30~=16G instructions.



              For a typical desktop computer with 4 GHz one core turbo and IPC of 2 (which is pessimistic for modern x86 CPUs) that amounts to 8 G instructions per second, which means brute force should take around two seconds if my math isn't completely of the charts wrong.



              So you can do a bunch of clever stuff but it won't save you more than two seconds of CPU time over just brute forcing it. And you can do much worse than brute force as OPs solution doesn't complete after a whole minute by computing ineffective sums, allocating a bunch of memory left right and center, generating permutations and what not.



              Edit: To prove my point:



              I implemented the brute force soloution:



              pe.cpp



              #include <iostream>

              int ssd(int n)
              int ans = 0;
              while(n)
              int d = n%10;
              n = n/10;
              ans += d*d;

              return ans;


              int main(int, char**)
              int n89 = 0;
              for(int n = 2; n < 10000000; n++)
              int s = ssd(n);
              while(s != 1 && s != 89)
              s = ssd(s);

              if(s==89)
              n89++;


              std::cout<<n89<<std::endl;



              And ran it, producing the correct solution in under half a second:



              $ g++ -O3 pe.cpp -o pe && time ./pe
              8581146

              real 0m0.423s
              user 0m0.423s
              sys 0m0.000s


              On my machine:



              $ cat /proc/cpuinfo | grep "model name" | tail -n 1
              model name : Intel(R) Core(TM) i7-8700K CPU @ 3.70GHz





              share|improve this answer














              Plenty of good answers have been given I'll just point out that 10 million is actually not a lot.



              The square sum of digits of 9999999 is 7*81=567 and this is the largest sum you can get. So to determine if any up to 7 digit number ends up as 1 or 89 cannot require more than 567 iterations of computing the sum of squared digits.



              Meaning that brute force 567*10M=5.67 G iterations of computing sum of digits squared will solve it. Sum of digits squared using the trivial integer division approach is 7 divisions with remainder, 6 additions and 7 multiples, plus loop overhead call it 30 instructions, so in total you'd need 5.67*30~=16G instructions.



              For a typical desktop computer with 4 GHz one core turbo and IPC of 2 (which is pessimistic for modern x86 CPUs) that amounts to 8 G instructions per second, which means brute force should take around two seconds if my math isn't completely of the charts wrong.



              So you can do a bunch of clever stuff but it won't save you more than two seconds of CPU time over just brute forcing it. And you can do much worse than brute force as OPs solution doesn't complete after a whole minute by computing ineffective sums, allocating a bunch of memory left right and center, generating permutations and what not.



              Edit: To prove my point:



              I implemented the brute force soloution:



              pe.cpp



              #include <iostream>

              int ssd(int n)
              int ans = 0;
              while(n)
              int d = n%10;
              n = n/10;
              ans += d*d;

              return ans;


              int main(int, char**)
              int n89 = 0;
              for(int n = 2; n < 10000000; n++)
              int s = ssd(n);
              while(s != 1 && s != 89)
              s = ssd(s);

              if(s==89)
              n89++;


              std::cout<<n89<<std::endl;



              And ran it, producing the correct solution in under half a second:



              $ g++ -O3 pe.cpp -o pe && time ./pe
              8581146

              real 0m0.423s
              user 0m0.423s
              sys 0m0.000s


              On my machine:



              $ cat /proc/cpuinfo | grep "model name" | tail -n 1
              model name : Intel(R) Core(TM) i7-8700K CPU @ 3.70GHz






              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Dec 11 at 1:14

























              answered Dec 11 at 0:44









              Emily L.

              11.4k12373




              11.4k12373











              • Completing a challenge from the Euler Project should ask for more than mere brute force. The criterium stated on the home page is that the algorithm shouldn't take more than one minute on an average machine to complete. Your machine isn't what I'd call average, and using C++ over other slower languages is already a boost. Even if the original poster devised a rather clumsy solution, I believe he's right in trying to beat brute force.
                – papagaga
                Dec 11 at 13:02










              • I disagree, some of the early questions can be solved with just pen and paper. While my machine is quite strong, it also computed the solution in less than 0.5 s on one core. So a machine with 1/120 the single core performance of mine should still make the 1 minute mark. So even something that has only a fifth of the performance of a VIA Eden 1 GHz low power CPU should still be able to compute it in under a minute... I bet even a Pentium 200 would make it under one minute (cpubenchmark.net/singleThread.html). I think that's below average, yes?
                – Emily L.
                Dec 11 at 22:30






              • 1




                @papagaga what I'm trying to say is that sometimes the brute force solution is the best one, or at least good enough. For example shaker sort (two sided bubble sort) of faster than quicksort on almost sorted arrays (codereview.stackexchange.com/a/159974/36120). Knowing when you can and should use an "inefficient" solution is an important skill for a software engineer.
                – Emily L.
                Dec 11 at 22:38










              • @EmiliL: ... I'm not sure how it happened, but I was mixing up minutes and seconds. You're absolutely right.
                – papagaga
                Dec 12 at 7:52
















              • Completing a challenge from the Euler Project should ask for more than mere brute force. The criterium stated on the home page is that the algorithm shouldn't take more than one minute on an average machine to complete. Your machine isn't what I'd call average, and using C++ over other slower languages is already a boost. Even if the original poster devised a rather clumsy solution, I believe he's right in trying to beat brute force.
                – papagaga
                Dec 11 at 13:02










              • I disagree, some of the early questions can be solved with just pen and paper. While my machine is quite strong, it also computed the solution in less than 0.5 s on one core. So a machine with 1/120 the single core performance of mine should still make the 1 minute mark. So even something that has only a fifth of the performance of a VIA Eden 1 GHz low power CPU should still be able to compute it in under a minute... I bet even a Pentium 200 would make it under one minute (cpubenchmark.net/singleThread.html). I think that's below average, yes?
                – Emily L.
                Dec 11 at 22:30






              • 1




                @papagaga what I'm trying to say is that sometimes the brute force solution is the best one, or at least good enough. For example shaker sort (two sided bubble sort) of faster than quicksort on almost sorted arrays (codereview.stackexchange.com/a/159974/36120). Knowing when you can and should use an "inefficient" solution is an important skill for a software engineer.
                – Emily L.
                Dec 11 at 22:38










              • @EmiliL: ... I'm not sure how it happened, but I was mixing up minutes and seconds. You're absolutely right.
                – papagaga
                Dec 12 at 7:52















              Completing a challenge from the Euler Project should ask for more than mere brute force. The criterium stated on the home page is that the algorithm shouldn't take more than one minute on an average machine to complete. Your machine isn't what I'd call average, and using C++ over other slower languages is already a boost. Even if the original poster devised a rather clumsy solution, I believe he's right in trying to beat brute force.
              – papagaga
              Dec 11 at 13:02




              Completing a challenge from the Euler Project should ask for more than mere brute force. The criterium stated on the home page is that the algorithm shouldn't take more than one minute on an average machine to complete. Your machine isn't what I'd call average, and using C++ over other slower languages is already a boost. Even if the original poster devised a rather clumsy solution, I believe he's right in trying to beat brute force.
              – papagaga
              Dec 11 at 13:02












              I disagree, some of the early questions can be solved with just pen and paper. While my machine is quite strong, it also computed the solution in less than 0.5 s on one core. So a machine with 1/120 the single core performance of mine should still make the 1 minute mark. So even something that has only a fifth of the performance of a VIA Eden 1 GHz low power CPU should still be able to compute it in under a minute... I bet even a Pentium 200 would make it under one minute (cpubenchmark.net/singleThread.html). I think that's below average, yes?
              – Emily L.
              Dec 11 at 22:30




              I disagree, some of the early questions can be solved with just pen and paper. While my machine is quite strong, it also computed the solution in less than 0.5 s on one core. So a machine with 1/120 the single core performance of mine should still make the 1 minute mark. So even something that has only a fifth of the performance of a VIA Eden 1 GHz low power CPU should still be able to compute it in under a minute... I bet even a Pentium 200 would make it under one minute (cpubenchmark.net/singleThread.html). I think that's below average, yes?
              – Emily L.
              Dec 11 at 22:30




              1




              1




              @papagaga what I'm trying to say is that sometimes the brute force solution is the best one, or at least good enough. For example shaker sort (two sided bubble sort) of faster than quicksort on almost sorted arrays (codereview.stackexchange.com/a/159974/36120). Knowing when you can and should use an "inefficient" solution is an important skill for a software engineer.
              – Emily L.
              Dec 11 at 22:38




              @papagaga what I'm trying to say is that sometimes the brute force solution is the best one, or at least good enough. For example shaker sort (two sided bubble sort) of faster than quicksort on almost sorted arrays (codereview.stackexchange.com/a/159974/36120). Knowing when you can and should use an "inefficient" solution is an important skill for a software engineer.
              – Emily L.
              Dec 11 at 22:38












              @EmiliL: ... I'm not sure how it happened, but I was mixing up minutes and seconds. You're absolutely right.
              – papagaga
              Dec 12 at 7:52




              @EmiliL: ... I'm not sure how it happened, but I was mixing up minutes and seconds. You're absolutely right.
              – papagaga
              Dec 12 at 7:52










              up vote
              3
              down vote













              int sumOfDigitsSquared(int n) 
              auto digits = std::to_string(n);
              int sum = 0;

              for (auto c : digits)
              sum += (c - '0') * (c - '0'); // I corrected the = into +=


              return sum;



              Conversions come with a performance hit, especially when the conversion implies memory allocation and copy, as here with std::to_string. It would make perfect sense if you had some use for the string, but you don't, since you return another int. And the math behind it is really basic:



              constexpr int sum_of_squared_digits(int n) 
              int res = 0;
              while (n)
              const int digit = n % 10;
              res += digit * digit;
              n /= 10;

              return res;



              I've marked it constexpr, only to hint that the whole algorithm could be performed at compile-time, but it wouldn't really be fair, so it won't.



              bool arrivesAt89(int n) 
              static auto cache = std::unordered_map<int,bool>();


              unordered_map might not be necessary in this case. A simple array would suffice, with 0 meaning unexplored, 1 ending with 1 and 89 ending with 89: it's even faster and all the memory allocation is done upfront.



               int m = n;
              while (m != 1)
              if(cache.find(m) != cache.end())
              return cache.find(m)->second;

              if (m == 89)
              auto perms = permutations(m);
              for (auto p : perms)
              cache.insert(p, true);

              return true;

              m = sumOfDigitsSquared(m);


              Here is I think the main weakness of your algorithm: you only cache the result for the number n and its permutations; all intermediary values are ignored, although they belong on the same path as n and would populate the map much faster.



               

              auto perms = permutations(n);
              for (auto p : perms)
              cache.insert(p, false);

              return false;



              Computing the permutations come with another heavy conversion, with memory allocation and copy (std::to_string) and a std::vector you won't use beyond feeding it to the static std::unordered_map inside your master function.



              std::vector<int> permutations(int n) 
              auto digits = std::to_string(n);
              std::vector<int> res;
              res.push_back(n);

              do
              res.push_back(stoi(digits));
              while (std::next_permutation(digits.begin(), digits.end()));


              Besides, it won't give you every permutation: if you want to go through all permutations with std::next_permutation, you need to start with a sorted std::string.



               return res;



              Anyway, I don't think that permutations are the best way of testing the numbers equivalence: you don't need it if you keep track of intermediary values, because permutations will result in the same squared digits' sum.



              Here what I'd find correctly optimized:



              auto precompute_results(int n) 
              std::vector<int> results(n, 0);
              // a vector instead of a map,
              // elements can be:
              // 0 = unexplored, 1 = ending in 1, 89 = ending in 89
              // n = on the same path as n
              for (int i = 1; i < n; ++i)
              auto cur = results[i] ? results[i] : i;
              while (true)
              results[i] = cur;

              return results;






              share|improve this answer


























                up vote
                3
                down vote













                int sumOfDigitsSquared(int n) 
                auto digits = std::to_string(n);
                int sum = 0;

                for (auto c : digits)
                sum += (c - '0') * (c - '0'); // I corrected the = into +=


                return sum;



                Conversions come with a performance hit, especially when the conversion implies memory allocation and copy, as here with std::to_string. It would make perfect sense if you had some use for the string, but you don't, since you return another int. And the math behind it is really basic:



                constexpr int sum_of_squared_digits(int n) 
                int res = 0;
                while (n)
                const int digit = n % 10;
                res += digit * digit;
                n /= 10;

                return res;



                I've marked it constexpr, only to hint that the whole algorithm could be performed at compile-time, but it wouldn't really be fair, so it won't.



                bool arrivesAt89(int n) 
                static auto cache = std::unordered_map<int,bool>();


                unordered_map might not be necessary in this case. A simple array would suffice, with 0 meaning unexplored, 1 ending with 1 and 89 ending with 89: it's even faster and all the memory allocation is done upfront.



                 int m = n;
                while (m != 1)
                if(cache.find(m) != cache.end())
                return cache.find(m)->second;

                if (m == 89)
                auto perms = permutations(m);
                for (auto p : perms)
                cache.insert(p, true);

                return true;

                m = sumOfDigitsSquared(m);


                Here is I think the main weakness of your algorithm: you only cache the result for the number n and its permutations; all intermediary values are ignored, although they belong on the same path as n and would populate the map much faster.



                 

                auto perms = permutations(n);
                for (auto p : perms)
                cache.insert(p, false);

                return false;



                Computing the permutations come with another heavy conversion, with memory allocation and copy (std::to_string) and a std::vector you won't use beyond feeding it to the static std::unordered_map inside your master function.



                std::vector<int> permutations(int n) 
                auto digits = std::to_string(n);
                std::vector<int> res;
                res.push_back(n);

                do
                res.push_back(stoi(digits));
                while (std::next_permutation(digits.begin(), digits.end()));


                Besides, it won't give you every permutation: if you want to go through all permutations with std::next_permutation, you need to start with a sorted std::string.



                 return res;



                Anyway, I don't think that permutations are the best way of testing the numbers equivalence: you don't need it if you keep track of intermediary values, because permutations will result in the same squared digits' sum.



                Here what I'd find correctly optimized:



                auto precompute_results(int n) 
                std::vector<int> results(n, 0);
                // a vector instead of a map,
                // elements can be:
                // 0 = unexplored, 1 = ending in 1, 89 = ending in 89
                // n = on the same path as n
                for (int i = 1; i < n; ++i)
                auto cur = results[i] ? results[i] : i;
                while (true)
                results[i] = cur;

                return results;






                share|improve this answer
























                  up vote
                  3
                  down vote










                  up vote
                  3
                  down vote









                  int sumOfDigitsSquared(int n) 
                  auto digits = std::to_string(n);
                  int sum = 0;

                  for (auto c : digits)
                  sum += (c - '0') * (c - '0'); // I corrected the = into +=


                  return sum;



                  Conversions come with a performance hit, especially when the conversion implies memory allocation and copy, as here with std::to_string. It would make perfect sense if you had some use for the string, but you don't, since you return another int. And the math behind it is really basic:



                  constexpr int sum_of_squared_digits(int n) 
                  int res = 0;
                  while (n)
                  const int digit = n % 10;
                  res += digit * digit;
                  n /= 10;

                  return res;



                  I've marked it constexpr, only to hint that the whole algorithm could be performed at compile-time, but it wouldn't really be fair, so it won't.



                  bool arrivesAt89(int n) 
                  static auto cache = std::unordered_map<int,bool>();


                  unordered_map might not be necessary in this case. A simple array would suffice, with 0 meaning unexplored, 1 ending with 1 and 89 ending with 89: it's even faster and all the memory allocation is done upfront.



                   int m = n;
                  while (m != 1)
                  if(cache.find(m) != cache.end())
                  return cache.find(m)->second;

                  if (m == 89)
                  auto perms = permutations(m);
                  for (auto p : perms)
                  cache.insert(p, true);

                  return true;

                  m = sumOfDigitsSquared(m);


                  Here is I think the main weakness of your algorithm: you only cache the result for the number n and its permutations; all intermediary values are ignored, although they belong on the same path as n and would populate the map much faster.



                   

                  auto perms = permutations(n);
                  for (auto p : perms)
                  cache.insert(p, false);

                  return false;



                  Computing the permutations come with another heavy conversion, with memory allocation and copy (std::to_string) and a std::vector you won't use beyond feeding it to the static std::unordered_map inside your master function.



                  std::vector<int> permutations(int n) 
                  auto digits = std::to_string(n);
                  std::vector<int> res;
                  res.push_back(n);

                  do
                  res.push_back(stoi(digits));
                  while (std::next_permutation(digits.begin(), digits.end()));


                  Besides, it won't give you every permutation: if you want to go through all permutations with std::next_permutation, you need to start with a sorted std::string.



                   return res;



                  Anyway, I don't think that permutations are the best way of testing the numbers equivalence: you don't need it if you keep track of intermediary values, because permutations will result in the same squared digits' sum.



                  Here what I'd find correctly optimized:



                  auto precompute_results(int n) 
                  std::vector<int> results(n, 0);
                  // a vector instead of a map,
                  // elements can be:
                  // 0 = unexplored, 1 = ending in 1, 89 = ending in 89
                  // n = on the same path as n
                  for (int i = 1; i < n; ++i)
                  auto cur = results[i] ? results[i] : i;
                  while (true)
                  results[i] = cur;

                  return results;






                  share|improve this answer














                  int sumOfDigitsSquared(int n) 
                  auto digits = std::to_string(n);
                  int sum = 0;

                  for (auto c : digits)
                  sum += (c - '0') * (c - '0'); // I corrected the = into +=


                  return sum;



                  Conversions come with a performance hit, especially when the conversion implies memory allocation and copy, as here with std::to_string. It would make perfect sense if you had some use for the string, but you don't, since you return another int. And the math behind it is really basic:



                  constexpr int sum_of_squared_digits(int n) 
                  int res = 0;
                  while (n)
                  const int digit = n % 10;
                  res += digit * digit;
                  n /= 10;

                  return res;



                  I've marked it constexpr, only to hint that the whole algorithm could be performed at compile-time, but it wouldn't really be fair, so it won't.



                  bool arrivesAt89(int n) 
                  static auto cache = std::unordered_map<int,bool>();


                  unordered_map might not be necessary in this case. A simple array would suffice, with 0 meaning unexplored, 1 ending with 1 and 89 ending with 89: it's even faster and all the memory allocation is done upfront.



                   int m = n;
                  while (m != 1)
                  if(cache.find(m) != cache.end())
                  return cache.find(m)->second;

                  if (m == 89)
                  auto perms = permutations(m);
                  for (auto p : perms)
                  cache.insert(p, true);

                  return true;

                  m = sumOfDigitsSquared(m);


                  Here is I think the main weakness of your algorithm: you only cache the result for the number n and its permutations; all intermediary values are ignored, although they belong on the same path as n and would populate the map much faster.



                   

                  auto perms = permutations(n);
                  for (auto p : perms)
                  cache.insert(p, false);

                  return false;



                  Computing the permutations come with another heavy conversion, with memory allocation and copy (std::to_string) and a std::vector you won't use beyond feeding it to the static std::unordered_map inside your master function.



                  std::vector<int> permutations(int n) 
                  auto digits = std::to_string(n);
                  std::vector<int> res;
                  res.push_back(n);

                  do
                  res.push_back(stoi(digits));
                  while (std::next_permutation(digits.begin(), digits.end()));


                  Besides, it won't give you every permutation: if you want to go through all permutations with std::next_permutation, you need to start with a sorted std::string.



                   return res;



                  Anyway, I don't think that permutations are the best way of testing the numbers equivalence: you don't need it if you keep track of intermediary values, because permutations will result in the same squared digits' sum.



                  Here what I'd find correctly optimized:



                  auto precompute_results(int n) 
                  std::vector<int> results(n, 0);
                  // a vector instead of a map,
                  // elements can be:
                  // 0 = unexplored, 1 = ending in 1, 89 = ending in 89
                  // n = on the same path as n
                  for (int i = 1; i < n; ++i)
                  auto cur = results[i] ? results[i] : i;
                  while (true)
                  results[i] = cur;

                  return results;







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Dec 11 at 8:03

























                  answered Dec 10 at 16:24









                  papagaga

                  4,089221




                  4,089221




















                      up vote
                      1
                      down vote













                      Sometimes it's good to remember the KISS principle.



                      With this in mind, first the squares of each digit is constant therefore a constant int to store those values will eliminate constantly multiplying them.



                      Integer math is much faster than string conversions.



                      One solution taking this in to account could look like this:



                      const int squares = 0,1,4,9,16,25,36,49,64,81 ;
                      bool IsSquareSum89(int num)

                      int sum = 0;
                      while (num != 89 && num != 1)

                      sum = 0;
                      while (num > 0)

                      int digit = num % 10;
                      sum += squares[digit];
                      num /= 10;

                      num = sum;

                      return num == 89;

                      int GetAnswer(int target)

                      int answer = 0;
                      for (int i = target - 1; i > 0; --i)

                      if (IsSquareSum89(i))

                      ++answer;


                      return answer;



                      On my machine this finds the answer in about 2 seconds.






                      share|improve this answer




















                      • So you optimize out a measly integer multiplication, that is right next to a division... that is wasted optimization effort. Plus: to fetch a value from an array requires an integer multiplication!
                        – Cris Luengo
                        Dec 11 at 1:43











                      • @CrisLuengo "to fetch a value from an array requires an integer multiplication" - Not always. For byte arrays, no operation is required. For an int array like this, rather than multiplication, you shift the index left by two, which is pretty cheap.
                        – Reinderien
                        Dec 11 at 1:50










                      • I'm pretty sure that the array access is more expensive than a multiplication: there is the memory access (maybe 100 × longer than a multiplication) and the offset calculation
                        – papagaga
                        Dec 11 at 8:02










                      • @papagaga - when I compare this code with EmilyL's , which uses the same basic algorithm, this code is slightly faster. The difference is probably close enough to say that they're even.
                        – tinstaafl
                        Dec 11 at 12:17










                      • You're right: in this case, since your array is small enough to hold in a cache line, access won't cost more than a multiplication -but still not much less either, whereas it makes the program a little more complicated.
                        – papagaga
                        Dec 11 at 13:06














                      up vote
                      1
                      down vote













                      Sometimes it's good to remember the KISS principle.



                      With this in mind, first the squares of each digit is constant therefore a constant int to store those values will eliminate constantly multiplying them.



                      Integer math is much faster than string conversions.



                      One solution taking this in to account could look like this:



                      const int squares = 0,1,4,9,16,25,36,49,64,81 ;
                      bool IsSquareSum89(int num)

                      int sum = 0;
                      while (num != 89 && num != 1)

                      sum = 0;
                      while (num > 0)

                      int digit = num % 10;
                      sum += squares[digit];
                      num /= 10;

                      num = sum;

                      return num == 89;

                      int GetAnswer(int target)

                      int answer = 0;
                      for (int i = target - 1; i > 0; --i)

                      if (IsSquareSum89(i))

                      ++answer;


                      return answer;



                      On my machine this finds the answer in about 2 seconds.






                      share|improve this answer




















                      • So you optimize out a measly integer multiplication, that is right next to a division... that is wasted optimization effort. Plus: to fetch a value from an array requires an integer multiplication!
                        – Cris Luengo
                        Dec 11 at 1:43











                      • @CrisLuengo "to fetch a value from an array requires an integer multiplication" - Not always. For byte arrays, no operation is required. For an int array like this, rather than multiplication, you shift the index left by two, which is pretty cheap.
                        – Reinderien
                        Dec 11 at 1:50










                      • I'm pretty sure that the array access is more expensive than a multiplication: there is the memory access (maybe 100 × longer than a multiplication) and the offset calculation
                        – papagaga
                        Dec 11 at 8:02










                      • @papagaga - when I compare this code with EmilyL's , which uses the same basic algorithm, this code is slightly faster. The difference is probably close enough to say that they're even.
                        – tinstaafl
                        Dec 11 at 12:17










                      • You're right: in this case, since your array is small enough to hold in a cache line, access won't cost more than a multiplication -but still not much less either, whereas it makes the program a little more complicated.
                        – papagaga
                        Dec 11 at 13:06












                      up vote
                      1
                      down vote










                      up vote
                      1
                      down vote









                      Sometimes it's good to remember the KISS principle.



                      With this in mind, first the squares of each digit is constant therefore a constant int to store those values will eliminate constantly multiplying them.



                      Integer math is much faster than string conversions.



                      One solution taking this in to account could look like this:



                      const int squares = 0,1,4,9,16,25,36,49,64,81 ;
                      bool IsSquareSum89(int num)

                      int sum = 0;
                      while (num != 89 && num != 1)

                      sum = 0;
                      while (num > 0)

                      int digit = num % 10;
                      sum += squares[digit];
                      num /= 10;

                      num = sum;

                      return num == 89;

                      int GetAnswer(int target)

                      int answer = 0;
                      for (int i = target - 1; i > 0; --i)

                      if (IsSquareSum89(i))

                      ++answer;


                      return answer;



                      On my machine this finds the answer in about 2 seconds.






                      share|improve this answer












                      Sometimes it's good to remember the KISS principle.



                      With this in mind, first the squares of each digit is constant therefore a constant int to store those values will eliminate constantly multiplying them.



                      Integer math is much faster than string conversions.



                      One solution taking this in to account could look like this:



                      const int squares = 0,1,4,9,16,25,36,49,64,81 ;
                      bool IsSquareSum89(int num)

                      int sum = 0;
                      while (num != 89 && num != 1)

                      sum = 0;
                      while (num > 0)

                      int digit = num % 10;
                      sum += squares[digit];
                      num /= 10;

                      num = sum;

                      return num == 89;

                      int GetAnswer(int target)

                      int answer = 0;
                      for (int i = target - 1; i > 0; --i)

                      if (IsSquareSum89(i))

                      ++answer;


                      return answer;



                      On my machine this finds the answer in about 2 seconds.







                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered Dec 10 at 22:20









                      tinstaafl

                      6,385827




                      6,385827











                      • So you optimize out a measly integer multiplication, that is right next to a division... that is wasted optimization effort. Plus: to fetch a value from an array requires an integer multiplication!
                        – Cris Luengo
                        Dec 11 at 1:43











                      • @CrisLuengo "to fetch a value from an array requires an integer multiplication" - Not always. For byte arrays, no operation is required. For an int array like this, rather than multiplication, you shift the index left by two, which is pretty cheap.
                        – Reinderien
                        Dec 11 at 1:50










                      • I'm pretty sure that the array access is more expensive than a multiplication: there is the memory access (maybe 100 × longer than a multiplication) and the offset calculation
                        – papagaga
                        Dec 11 at 8:02










                      • @papagaga - when I compare this code with EmilyL's , which uses the same basic algorithm, this code is slightly faster. The difference is probably close enough to say that they're even.
                        – tinstaafl
                        Dec 11 at 12:17










                      • You're right: in this case, since your array is small enough to hold in a cache line, access won't cost more than a multiplication -but still not much less either, whereas it makes the program a little more complicated.
                        – papagaga
                        Dec 11 at 13:06
















                      • So you optimize out a measly integer multiplication, that is right next to a division... that is wasted optimization effort. Plus: to fetch a value from an array requires an integer multiplication!
                        – Cris Luengo
                        Dec 11 at 1:43











                      • @CrisLuengo "to fetch a value from an array requires an integer multiplication" - Not always. For byte arrays, no operation is required. For an int array like this, rather than multiplication, you shift the index left by two, which is pretty cheap.
                        – Reinderien
                        Dec 11 at 1:50










                      • I'm pretty sure that the array access is more expensive than a multiplication: there is the memory access (maybe 100 × longer than a multiplication) and the offset calculation
                        – papagaga
                        Dec 11 at 8:02










                      • @papagaga - when I compare this code with EmilyL's , which uses the same basic algorithm, this code is slightly faster. The difference is probably close enough to say that they're even.
                        – tinstaafl
                        Dec 11 at 12:17










                      • You're right: in this case, since your array is small enough to hold in a cache line, access won't cost more than a multiplication -but still not much less either, whereas it makes the program a little more complicated.
                        – papagaga
                        Dec 11 at 13:06















                      So you optimize out a measly integer multiplication, that is right next to a division... that is wasted optimization effort. Plus: to fetch a value from an array requires an integer multiplication!
                      – Cris Luengo
                      Dec 11 at 1:43





                      So you optimize out a measly integer multiplication, that is right next to a division... that is wasted optimization effort. Plus: to fetch a value from an array requires an integer multiplication!
                      – Cris Luengo
                      Dec 11 at 1:43













                      @CrisLuengo "to fetch a value from an array requires an integer multiplication" - Not always. For byte arrays, no operation is required. For an int array like this, rather than multiplication, you shift the index left by two, which is pretty cheap.
                      – Reinderien
                      Dec 11 at 1:50




                      @CrisLuengo "to fetch a value from an array requires an integer multiplication" - Not always. For byte arrays, no operation is required. For an int array like this, rather than multiplication, you shift the index left by two, which is pretty cheap.
                      – Reinderien
                      Dec 11 at 1:50












                      I'm pretty sure that the array access is more expensive than a multiplication: there is the memory access (maybe 100 × longer than a multiplication) and the offset calculation
                      – papagaga
                      Dec 11 at 8:02




                      I'm pretty sure that the array access is more expensive than a multiplication: there is the memory access (maybe 100 × longer than a multiplication) and the offset calculation
                      – papagaga
                      Dec 11 at 8:02












                      @papagaga - when I compare this code with EmilyL's , which uses the same basic algorithm, this code is slightly faster. The difference is probably close enough to say that they're even.
                      – tinstaafl
                      Dec 11 at 12:17




                      @papagaga - when I compare this code with EmilyL's , which uses the same basic algorithm, this code is slightly faster. The difference is probably close enough to say that they're even.
                      – tinstaafl
                      Dec 11 at 12:17












                      You're right: in this case, since your array is small enough to hold in a cache line, access won't cost more than a multiplication -but still not much less either, whereas it makes the program a little more complicated.
                      – papagaga
                      Dec 11 at 13:06




                      You're right: in this case, since your array is small enough to hold in a cache line, access won't cost more than a multiplication -but still not much less either, whereas it makes the program a little more complicated.
                      – papagaga
                      Dec 11 at 13:06

















                      draft saved

                      draft discarded
















































                      Thanks for contributing an answer to Code Review Stack Exchange!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid


                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.

                      Use MathJax to format equations. MathJax reference.


                      To learn more, see our tips on writing great answers.





                      Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                      Please pay close attention to the following guidance:


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid


                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.

                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209303%2fproject-euler-92-count-sum-squared-digits-chains-that-reach-89%23new-answer', 'question_page');

                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown






                      Popular posts from this blog

                      How to check contact read email or not when send email to Individual?

                      Bahrain

                      Postfix configuration issue with fips on centos 7; mailgun relay