Unusual Speed Difference between Python and C++

后端 未结 17 2325
庸人自扰
庸人自扰 2020-12-22 21:25

I recently wrote a short algorithm to calculate happy numbers in python. The program allows you to pick an upper bound and it will determine all the happy numbers below it.

17条回答
  •  没有蜡笔的小新
    2020-12-22 21:50

    Here is another way that relies on memorising all the numbers already explored. I obtain a factor x4-5, which is oddly stable against DrAsik's code for 1000 and 1000000, I expected the cache to be more efficient the more numbers we were exploring. Otherwise, the same kind of classic optimizations have been applied. BTW, if the compiler accepts NRVO (/RNVO ? I never remember the exact term) or rvalue references, we wouldn't need to pass the vector as an out parameter.

    NB: micro-optimizations are still possible IMHO, and moreover the caching is naive as it allocates much more memory than really needed.

    enum Status {
        never_seen,
        being_explored,
        happy,
        unhappy
    };
    
    char const* toString[] = { "never_seen", "being_explored", "happy", "unhappy" };
    
    
    inline size_t sum_squares(size_t i) {
        size_t s = 0;
        while (i) {
            const size_t digit = i%10;
            s += digit * digit;
            i /= 10;
        }
        return s ;
    }
    
    struct Cache {
        Cache(size_t dim) : m_cache(dim, never_seen) {}
        void set(size_t n, Status status) {
            if (m_cache.size() <= n) {
                m_cache.resize(n+1, never_seen);
            }
            m_cache[n] = status;
            // std::cout << "(c[" << n << "]<-"< m_cache;
    };
    
    void search_happy_lh(size_t upper_bound, std::vector & happy_numbers)
    {
        happy_numbers.clear();
        happy_numbers.reserve(upper_bound); // it doesn't improve much the performances
    
        Cache cache(upper_bound+1);
        std::vector current_stack;
    
        cache.set(1,happy);
        happy_numbers.push_back(1);
        for (size_t i = 2; i<=upper_bound ; ++i) {
            // std::cout << "\r" << i << std::flush;
            current_stack.clear();
            size_t s= i;
            while ( s != 1 && cache[s]==never_seen)
            {
                current_stack.push_back(s);
                cache.set(s, being_explored);
                s = sum_squares(s);
                // std::cout << " - " << s << std::flush;
            }
            const Status update_with = (cache[s]==being_explored ||cache[s]==unhappy) ? unhappy : happy;
            // std::cout << " => " << s << ":" << toString[update_with] << std::endl;
            for (size_t j=0; j!=current_stack.size(); ++j) {
                cache.set(current_stack[j], update_with);
            }
            if (cache[i] == happy) {
                happy_numbers.push_back(i);
            }
        }
    }
    

提交回复
热议问题