TheAlgorithms/Python · error · ValueError

math domain error

Error message

math domain error

What it means

Raised by gamma_iterative in maths/gamma.py when num <= 0. The function approximates the Gamma function via numerical integration of exp(-x)*x^(z-1) from 0 to infinity, which diverges for non-positive z, so the code explicitly mirrors CPython's math.gamma by raising ValueError('math domain error'). This is a precondition check at the top of the function, before scipy's quad is called.

Source

Thrown at maths/gamma.py:45

    >>> gamma_iterative(0)
    Traceback (most recent call last):
        ...
    ValueError: math domain error
    >>> gamma_iterative(9)
    40320.0
    >>> from math import gamma as math_gamma
    >>> all(.99999999 < gamma_iterative(i) / math_gamma(i) <= 1.000000001
    ...     for i in range(1, 50))
    True
    >>> gamma_iterative(-1)/math_gamma(-1) <= 1.000000001
    Traceback (most recent call last):
        ...
    ValueError: math domain error
    >>> gamma_iterative(3.3) - math_gamma(3.3) <= 0.00000001
    True
    """
    if num <= 0:
        raise ValueError("math domain error")

    return quad(integrand, 0, inf, args=(num))[0]


def integrand(x: float, z: float) -> float:
    return math.pow(x, z - 1) * math.exp(-x)


def gamma_recursive(num: float) -> float:
    """
    Calculates the value of Gamma function of num
    where num is either an integer (1, 2, 3..) or a half-integer (0.5, 1.5, 2.5 ...).
    Implemented using recursion
    Examples:
    >>> from math import isclose, gamma as math_gamma
    >>> gamma_recursive(0.5)
    1.7724538509055159
    >>> gamma_recursive(1)

View on GitHub (pinned to f5988cc097)

Solutions

  1. Only call gamma_iterative with strictly positive arguments (num > 0).
  2. If negative or zero inputs are legitimate in your domain, switch to a library that supports Gamma's analytic continuation or reflection formula (e.g. scipy.special.gamma handles negatives at non-integers; use math.gamma only for num > 0).
  3. Guard call sites: validate num > 0 before calling and branch to your own handling otherwise.

Example fix

// before
val = gamma_iterative(x)  # x may be <= 0

// after
if x <= 0:
    raise ValueError(f"gamma_iterative requires num > 0, got {x}")
val = gamma_iterative(x)
Defensive patterns

Strategy: validation

Validate before calling

def safe_gamma_iterative(num: float) -> float:
    if num <= 0:
        raise ValueError(f"gamma defined only for num > 0, got {num}")
    return gamma_iterative(num)

Type guard

def is_positive_real(num) -> bool:
    return isinstance(num, (int, float)) and num > 0

Try / catch

try:
    val = gamma_iterative(x)
except ValueError as e:
    if 'domain' in str(e):
        # handle non-positive input
        ...
    raise

Prevention

When it happens

Trigger: Calling gamma_iterative with num = 0 or any negative value, e.g. gamma_iterative(-1) or gamma_iterative(0). Any num <= 0 hits the 'if num <= 0' branch and raises immediately.

Common situations: Porting code from math.gamma and assuming different domain rules; passing user-supplied or computed values (e.g. shifted by a subtraction) that can reach 0 or below; looping over ranges that include 0 without filtering.

Related errors


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