Является ли убедительным, что теперь scipy.misc.comb
действительно быстрее, чем специальная реализация?
В соответствии со старым ответом Статистика: комбинации в Python эта функция доморощенного быстрее scipy.misc.comb
при расчете комбинаций nCr
:
def choose(n, k):
"""
A fast way to calculate binomial coefficients by Andrew Dalke (contrib).
"""
if 0 <= k <= n:
ntok = 1
ktok = 1
for t in xrange(1, min(k, n - k) + 1):
ntok *= n
ktok *= t
n -= 1
return ntok // ktok
else:
return 0
Но после запуска некоторых тестов на моей машине это не похоже на этот случай, используя этот script:
from scipy.misc import comb
import random, time
def choose(n, k):
"""
A fast way to calculate binomial coefficients by Andrew Dalke (contrib).
"""
if 0 <= k <= n:
ntok = 1
ktok = 1
for t in xrange(1, min(k, n - k) + 1):
ntok *= n
ktok *= t
n -= 1
return ntok // ktok
else:
return 0
def timing(f):
def wrap(*args):
time1 = time.time()
ret = f(*args)
time2 = time.time()
print '%s function took %0.3f ms' % (f.__name__, (time2-time1)*1000.0)
return ret
return wrap
@timing
def test_func(combination_func, nk):
for n,k in nk:
combination_func(n, k)
nk = []
for _ in range(1000):
n = int(random.random() * 10000)
k = random.randint(0,n)
nk.append((n,k))
test_func(comb, nk)
test_func(choose, nk)
Я получаю следующий вывод:
$ python test.py
/usr/lib/python2.7/dist-packages/scipy/misc/common.py:295: RuntimeWarning: overflow encountered in exp
vals = exp(lgam(N+1) - lgam(N-k+1) - lgam(k+1))
999
test_func function took 32.869 ms
999
test_func function took 1859.125 ms
$ python test.py
/usr/lib/python2.7/dist-packages/scipy/misc/common.py:295: RuntimeWarning: overflow encountered in exp
vals = exp(lgam(N+1) - lgam(N-k+1) - lgam(k+1))
999
test_func function took 32.265 ms
999
test_func function took 1878.550 ms
Прошел ли тест профилирования времени, что новый scipy.misc.comb
быстрее, чем функция ad-hoc choose()
? Есть ли какая-либо ошибка в моем тесте script, что делает время неточным?
Почему теперь scipy.misc.comb
работает быстрее? Это связано с некоторыми трюками cython
/c
?
EDITED
После комментария @WarrenWeckesser:
Используя приближение с плавающей запятой по умолчанию при использовании scipy.misc.comb()
, вычисление прерывается из-за переполнения с плавающей запятой.
(см. http://docs.scipy.org/doc/scipy-0.16.0/reference/generated/scipy.misc.comb.html для документации)
При тестировании с exact=True
, который вычисляет с длинными целыми числами вместо плавающей запятой, используя приведенную ниже функцию, он намного медленнее при вычислении 1000 комбинаций:
@timing
def test_func(combination_func, nk):
for i, (n,k) in enumerate(nk):
combination_func(n, k, exact=True)
[выход]:
$ python test.py
test_func function took 3312.211 ms
test_func function took 1764.523 ms
$ python test.py
test_func function took 3320.198 ms
test_func function took 1782.280 ms