Skip to content

The upper incomplete gamma function - #2077

Merged
Rafael-SOWNet merged 1 commit into
masterfrom
the-incomplete-gamma-function
Oct 22, 2026
Merged

Rafael-SOWNet merged 1 commit into
masterfrom
the-incomplete-gamma-function

Conversation

@Rafael-SOWNet

Copy link
Copy Markdown
Member

Part of #2075.

The node. With a second argument, gamma(a, z) is the upper incomplete gamma function Gamma(a, z) = int_z^oo t^(a - 1) e^(-t) dt, as Mathematica's Gamma[a, z] and mpmath's gammainc(a, z) are. With one argument, gamma is still Gamma(x). A second argument used to be a FunctionArgumentCountException.

  • Branch. z^a takes its principal branch, so the cut is the negative real axis, which keeps the value from above.
  • Printing. In LaTeX it is \Gamma\left(a, z\right), and in SymPy uppergamma.
  • Derivative. In z it is -z^(a - 1) e^(-z). If the parameter varies, it declines.
  • Exact forms.
    • A whole a >= 1 is (n - 1)! e^(-z) times a polynomial (DLMF 8.4.8).
    • a = 1/2 is sqrt(pi) erfc(sqrt(z)) (8.4.6).
    • Gamma(a, 0) is Gamma(a) for a positive a.

Evaluation is to the working precision for any complex a and z. Which method runs:

  • Legendre's continued fraction (8.9.2), by the modified Lentz algorithm, where |z| > 2|a| + 10, either in the right half-plane or past (P + 5) ln 10. Near the negative real axis at a moderate |z| it stops short of the value: Gamma(1/2, -10) was wrong in its fourth digit. With |a| large against |z| it converges slowly: Gamma(100, 1/10 - 10 i) had the wrong imaginary part. Both cases were measured, and both go to the series.
  • The series everywhere else: Gamma(a) less the lower function's series (8.7.1), with twice |z|/ln 10 guard digits, and more where the difference shows it cancelled more.
  • A whole a <= 0, where Gamma(a) has a pole: E_1(z) by its series, and the recurrence (8.4.15).
  • Real values. The value is exactly real where it is real: for a positive z, and for a whole a >= 1 at any real z.
  • No floor at zero. Each part is accurate to its own size, so nothing is rounded onto zero by size. Gamma(1/2, 300) is 3e-132, and Gamma(100, -5 + i/10) has an imaginary part 1e-86 of its real part.

Against mpmath's gammainc:

Precision Points Agreement Covers
100 digits 168 1e-90 (worst 3.8e-100)
300 digits 54 1e-290 orders within 1e-30 of a pole, both sides of the cut, `

Cost: about 5 ms per evaluation at a hundred digits. At three hundred digits, an order near a pole costs tens of seconds the first time, mostly in setting up Gamma(a) at each new precision.

Not here: the integration rules, and the corpus harness reading Rubi's file 8.6. Those are #2075's next steps.

IncompleteGammaTest covers:

  • ten values against mpmath, including the poles, the continued fraction far below the floor at zero, the cut, and a complex parameter;
  • the elementary forms;
  • the derivative, and the case where it declines;
  • parsing and printing.

Results:

  • Unit suite: passes (16,856).
  • MCP tests: pass (329). The MCP syntax resource names the new form.
  • Parser: regenerated, with its classes internal.
  • PublicApi.txt: gains the node, the kernel and MathS.IncompleteGamma.
  • BREAKING-CHANGES: has the entry.

🤖 Generated with Claude Code

https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura

gamma(a, z) with a second argument is the upper incomplete gamma function
Gamma(a, z) = int_z^oo t^(a - 1) e^(-t) dt, as Mathematica's Gamma[a, z]
and mpmath's gammainc(a, z) are; with one, gamma is still Gamma(x), and a
second argument was a parse error. z^a takes its principal branch, so the
cut is the negative real axis, which keeps the value from above. It is
printed so, in LaTeX as \Gamma(a, z) and in SymPy as uppergamma, and its
derivative in z is -z^(a - 1) e^(-z); a parameter that varies declines. A
whole a >= 1 is (n - 1)! e^(-z) times a polynomial (DLMF 8.4.8), a half is
sqrt(pi) erfc(sqrt(z)) (8.4.6), and Gamma(a, 0) is Gamma(a).

It is evaluated to the working precision for any complex a and z. Where
|z| > 2|a| + 10, in the right half-plane or past (P + 5) ln 10, it is
Legendre's continued fraction (8.9.2) by the modified Lentz algorithm;
elsewhere it is Gamma(a) less the lower one's series (8.7.1), with twice
|z|/ln 10 guard digits and more where the difference shows it cancelled
more; and at a whole a <= 0, where Gamma(a) has a pole, E_1(z) by its
series and the recurrence (8.4.15). It is real exactly where it is real:
for a positive z, and for a whole a >= 1 at any real z. It agrees with
mpmath at 168 points to 1e-90 at a hundred digits and at 54 to 1e-290 at
three hundred, near the poles and on the cut.

Part of #2075.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura
@Rafael-SOWNet Rafael-SOWNet added this to the 2.7.0 milestone Oct 22, 2026
@Rafael-SOWNet
Rafael-SOWNet merged commit 865744b into master Oct 22, 2026
35 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in AngouriMath Oct 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant