Вот еще одна альтернатива. Первоначально он был написан на C ++, поэтому его можно перенести в C ++ для целого числа с конечной точностью (например, __int64). Преимущество состоит в том, что (1) он включает в себя только целочисленные операции и (2) он избегает раздувания целочисленного значения, выполняя последовательные пары умножения и деления. Я проверил результат с помощью треугольника Паскаля Нас Банова, он получил правильный ответ:
def choose(n,r):
"""Computes n! / (r! (n-r)!) exactly. Returns a python long int."""
assert n >= 0
assert 0 <= r <= n
c = 1L
denom = 1
for (num,denom) in zip(xrange(n,n-r,-1), xrange(1,r+1,1)):
c = (c * num) // denom
return c
Обоснование: чтобы минимизировать количество умножений и делений, мы переписываем выражение как
n! n(n-1)...(n-r+1)
--------- = ----------------
r!(n-r)! r!
Чтобы избежать максимально возможного переполнения умножения, мы будем оценивать в следующем порядке СТРОГО, слева направо:
n / 1 * (n-1) / 2 * (n-2) / 3 * ... * (n-r+1) / r
Мы можем показать, что целочисленная арифметическая операция в этом порядке является точной (т.е. нет ошибки округления).