TheAlgorithms/Python · error · NotImplementedError

num must be an integer or a half-integer

Error message

num must be an integer or a half-integer

What it means

Raised by gamma_recursive in maths/gamma.py when the fractional part of num is neither 0 nor 0.5. The recursion only has base cases for integers and half-integers (num == 0.5 returns sqrt(pi), num == 1 returns 1.0), so any other fractional input cannot terminate correctly and is rejected with NotImplementedError. This is an intentional API limitation, not a bug.

Source

Thrown at maths/gamma.py:100

    >>> gamma_recursive(-4)
    Traceback (most recent call last):
        ...
    ValueError: math domain error
    >>> gamma_recursive(172)
    Traceback (most recent call last):
        ...
    OverflowError: math range error
    >>> gamma_recursive(1.1)
    Traceback (most recent call last):
        ...
    NotImplementedError: num must be an integer or a half-integer
    """
    if num <= 0:
        raise ValueError("math domain error")
    if num > 171.5:
        raise OverflowError("math range error")
    elif num - int(num) not in (0, 0.5):
        raise NotImplementedError("num must be an integer or a half-integer")
    elif num == 0.5:
        return math.sqrt(math.pi)
    else:
        return 1.0 if num == 1 else (num - 1) * gamma_recursive(num - 1)


if __name__ == "__main__":
    from doctest import testmod

    testmod()
    num = 1.0
    while num:
        num = float(input("Gamma of: "))
        print(f"gamma_iterative({num}) = {gamma_iterative(num)}")
        print(f"gamma_recursive({num}) = {gamma_recursive(num)}")
        print("\nEnter 0 to exit...")

View on GitHub (pinned to f5988cc097)

Solutions

  1. Use gamma_iterative(num) or math.gamma(num) for arbitrary positive floats.
  2. If you expect an integer/half-integer but floats drift in, round to the nearest 0.5 before calling: num = round(num * 2) / 2.
  3. Catch NotImplementedError explicitly to detect unsupported inputs in generic pipelines.

Example fix

// before
val = gamma_recursive(3.3)  # NotImplementedError

// after
from maths.gamma import gamma_iterative
val = gamma_iterative(3.3)  # supports any positive float
Defensive patterns

Strategy: fallback

Validate before calling

num = round(num * 2) / 2  # snap to nearest half-integer if drift expected
if num <= 0 or num > 171.5:
    raise ValueError(f"out of range: {num}")

Type guard

def is_supported_gamma_input(num) -> bool:
    return 0 < num <= 171.5 and (num - int(num)) in (0, 0.5)

Try / catch

try:
    val = gamma_recursive(num)
except NotImplementedError:
    val = gamma_iterative(num)  # handles arbitrary positive floats

Prevention

When it happens

Trigger: Calling gamma_recursive(1.1), gamma_recursive(2.7), or any value where num - int(num) is not 0 or 0.5. Note the check happens after the num <= 0 and num > 171.5 checks.

Common situations: Assuming gamma_recursive has the same domain as math.gamma or gamma_iterative (which accept any positive float); passing computed floating-point values that pick up small fractional residues (e.g. 2.0000000001 after arithmetic); testing with arbitrary decimals.

Related errors


AI-assisted analysis of TheAlgorithms/Python@f5988cc097 (2026-08-14). Data as JSON: /api/errors/203131415f27f10f. Report an issue: GitHub.