Avoid spurious overflow in fp gammaprod (#1150)

* Avoid spurious overflow in fp gammaprod

fp.binomial(1100, 1) raised OverflowError even though the result is
exactly 1100: gammaprod multiplies the individual gamma values, and
gamma(1101) exceeds the double range although the quotient does not.

Fall back to evaluating the regular numerator/denominator in log space
when a term overflows, so the quotient is computed whenever it is
representable. Genuinely out-of-range results, such as
fp.binomial(1100, 550), still raise OverflowError.

Closes #493
This commit is contained in:
Sanjay Santhanam
2026-08-02 21:09:31 -07:00
committed by GitHub
parent 255d98ff98
commit c90e242741
2 changed files with 22 additions and 2 deletions
+13 -2
View File
@@ -31,8 +31,19 @@ def gammaprod(ctx, a, b, _infsign=False):
i = poles_num.pop()
j = poles_den.pop()
p *= (-1)**(i+j) * ctx.gamma(1-j) / ctx.gamma(1-i)
for x in regular_num: p *= ctx.gamma(x)
for x in regular_den: p /= ctx.gamma(x)
try:
q = ctx.one
for x in regular_num: q *= ctx.gamma(x)
for x in regular_den: q /= ctx.gamma(x)
except OverflowError:
# In the fp context an individual gamma value can exceed the
# double range even when the quotient is representable, e.g.
# binomial(1100, 1). Evaluate the regular part in log space.
s = ctx.zero
for x in regular_num: s += ctx.loggamma(x)
for x in regular_den: s -= ctx.loggamma(x)
q = ctx.exp(s)
p *= q
finally:
ctx.prec = orig
return +p
+9
View File
@@ -1811,3 +1811,12 @@ def test_issue_491():
def test_issue_521():
assert fp.ff(1, -fp.inf) == 0.0
assert fp.isnan(fp.ff(1, fp.inf))
def test_issue_493():
assert ae(fp.binomial(1100, 1), 1100.0)
assert ae(fp.binomial(1100, 1099), 1100.0)
assert fp.binomial(1100, 0) == 1.0
assert ae(fp.rf(1100, 1), 1100.0)
assert ae(fp.beta(1100, 1), 1/1100)
assert ae(fp.binomial(5, 2), 10.0)
pytest.raises(OverflowError, lambda: fp.binomial(1100, 550))