Unusual Speed Difference between Python and C++

后端 未结 17 2298
庸人自扰
庸人自扰 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:36

    There's a new, radically faster version as a separate answer, so this answer is deprecated.


    I rewrote your algorithm by making it cache whenever it finds the number to be happy or unhappy. I also tried to make it as pythonic as I could, for example by creating separate functions digits() and happy(). Sorry for using Python 3, but I get to show off a couple a useful things from it as well.

    This version is much faster. It runs at 1.7s which is 10 times faster than your original program that takes 18s (well, my MacBook is quite old and slow :) )

    #!/usr/bin/env python3
    
    from timeit import Timer
    from itertools import count
    
    print_numbers = False
    upperBound = 10**5  # Default value, can be overidden by user.
    
    
    def digits(x:'nonnegative number') -> "yields number's digits":
        if not (x >= 0): raise ValueError('Number should be nonnegative')
        while x:
            yield x % 10
            x //= 10
    
    
    def happy(number, known = {1}, happies = {1}) -> 'True/None':
        '''This function tells if the number is happy or not, caching results.
    
        It uses two static variables, parameters known and happies; the
        first one contains known happy and unhappy numbers; the second 
        contains only happy ones.
    
        If you want, you can pass your own known and happies arguments. If
        you do, you should keep the assumption commented out on the 1 line.
    
        '''
    
    #        assert 1 in known and happies <= known  # <= is expensive
    
        if number in known:
            return number in happies
    
        history = set()
        while True:
            history.add(number)
            number = sum(x**2 for x in digits(number))
            if number in known or number in history:
                break
    
        known.update(history)
        if number in happies:
            happies.update(history)
            return True
    
    
    def calcMain():
        happies = {x for x in range(upperBound) if happy(x) }
        if print_numbers:
            print(happies)
    
    
    if __name__ == '__main__':
        upperBound = eval(
                input("Pick an upper bound [default {0}]: "
                        .format(upperBound)).strip()
                or repr(upperBound))
        result = Timer(calcMain).timeit(1)
        print ('This computation took {0} seconds'.format(result))
    

提交回复
热议问题