При попытке написать ответ на другой вопрос SO произошло нечто странное.
В основном я придумал однострочный gcd и сказал что он может быть медленнее из-за рекурсии
gcd = lambda a,b : a if not b else gcd(b, a % b)
здесь простой тест:
assert gcd(10, 3) == 1 and gcd(21, 7) == 7 and gcd(100, 1000) == 100
вот несколько тестов:
timeit.Timer('gcd(2**2048, 2**2048+123)', setup = 'from fractions import gcd').repeat(3, 100)
# [0.0022919178009033203, 0.0016410350799560547, 0.0016489028930664062]
timeit.Timer('gcd(2**2048, 2**2048+123)', setup = 'gcd = lambda a,b : a if not b else gcd(b, a % b)').repeat(3, 100)
# [0.0020480155944824219, 0.0016460418701171875, 0.0014090538024902344]
Что ж, интересно, я ожидал, что будет намного медленнее, но тайминги довольно близки, ? возможно, проблема заключается в импорте модуля...
>>> setup = '''
... def gcd(a, b):
... """Calculate the Greatest Common Divisor of a and b.
...
... Unless b==0, the result will have the same sign as b (so that when
... b is divided by it, the result comes out positive).
... """
... while b:
... a, b = b, a%b
... return a
... '''
>>> timeit.Timer('gcd(2**2048, 2**2048+123)', setup = setup).repeat(3, 100)
[0.0015637874603271484, 0.0014810562133789062, 0.0014750957489013672]
нет, тайминги довольно близки, ок, давайте попробуем увеличить значения.
timeit.Timer('gcd(2**9048, 2**248212)', setup = 'gcd = lambda a,b : a if not b else gcd(b, a % b)').repeat(3, 100) [2.866894006729126, 2.8396279811859131, 2.8353509902954102]
[2.866894006729126, 2.8396279811859131, 2.8353509902954102]
timeit.Timer('gcd(2**9048, 2**248212)', setup = setup).repeat(3, 100)
[2.8533108234405518, 2.8411397933959961, 2.8430981636047363]
интересно Интересно, что происходит?
Я всегда предполагал, что рекурсия медленнее из-за накладных расходов на вызов функции, являются ли лямбда-выражения исключением? и почему я не достиг предела рекурсии?
Если реализовано с использованием def
, я попаду сразу, если я увеличу глубину рекурсии до чего-то вроде 10**9
, я фактически получу ошибку сегментации
, вероятно, стек переполнение...
Обновление
>>> setup = '''
... import sys
... sys.setrecursionlimit(10**6)
...
... def gcd(a, b):
... return a if not b else gcd(b, a % b)
... '''
>>>
>>> timeit.Timer('gcd(2**9048, 2**248212)', setup = 'gcd = lambda a,b:a if not b else gcd(b, a%b)').repeat(3, 100)
[3.0647969245910645, 3.0081429481506348, 2.9654929637908936]
>>> timeit.Timer('gcd(2**9048, 2**248212)', setup = 'from fractions import gcd').repeat(3, 100)
[3.0753359794616699, 2.97499680519104, 3.0096950531005859]
>>> timeit.Timer('gcd(2**9048, 2**248212)', setup = setup).repeat(3, 100)
[3.0334799289703369, 2.9955930709838867, 2.9726388454437256]
>>>
еще больше озадачивает...