TheAlgorithms/Python · error · ValueError

double_factorial_recursive() only accepts integral values

Error message

double_factorial_recursive() only accepts integral values

What it means

Raised by double_factorial_recursive() in maths/double_factorial.py when n is not an int. The double factorial n!! recursively multiplies n*(n-2)*... and is only defined on integers, so float inputs (0.1) and other types are rejected with ValueError before recursion starts.

Source

Thrown at maths/double_factorial.py:22

    Recursion can be costly for large numbers.

    To learn about the theory behind this algorithm:
    https://en.wikipedia.org/wiki/Double_factorial

    >>> from math import prod
    >>> all(double_factorial_recursive(i) == prod(range(i, 0, -2)) for i in range(20))
    True
    >>> double_factorial_recursive(0.1)
    Traceback (most recent call last):
        ...
    ValueError: double_factorial_recursive() only accepts integral values
    >>> double_factorial_recursive(-1)
    Traceback (most recent call last):
        ...
    ValueError: double_factorial_recursive() not defined for negative values
    """
    if not isinstance(n, int):
        raise ValueError("double_factorial_recursive() only accepts integral values")
    if n < 0:
        raise ValueError("double_factorial_recursive() not defined for negative values")
    return 1 if n <= 1 else n * double_factorial_recursive(n - 2)


def double_factorial_iterative(num: int) -> int:
    """
    Compute double factorial using iterative method.

    To learn about the theory behind this algorithm:
    https://en.wikipedia.org/wiki/Double_factorial

    >>> from math import prod
    >>> all(double_factorial_iterative(i) == prod(range(i, 0, -2)) for i in range(20))
    True
    >>> double_factorial_iterative(0.1)
    Traceback (most recent call last):
        ...

View on GitHub (pinned to f5988cc097)

Solutions

  1. Convert whole floats first: double_factorial_recursive(int(n)) after checking n == int(n).
  2. Use math.prod(range(n, 0, -2)) yourself if you need leniency for numpy integer types.
  3. Keep the input in int form end-to-end (avoid float round-trips through JSON or division).

Example fix

# before
double_factorial_recursive(9.0)  # ValueError

# after
n = 9.0
assert n == int(n)
double_factorial_recursive(int(n))  # 945
Defensive patterns

Strategy: type-guard

Validate before calling

if not isinstance(n, int) or isinstance(n, bool):
    if n != int(n):
        raise ValueError('n must be integral')
    n = int(n)

Type guard

def is_integral(n) -> bool:
    return isinstance(n, int) or (isinstance(n, float) and n == int(n))

Try / catch

try:
    r = double_factorial_recursive(n)
except ValueError as e:
    if 'integral values' in str(e):
        r = double_factorial_recursive(int(n))
    else:
        raise

Prevention

When it happens

Trigger: Calling double_factorial_recursive(0.1), double_factorial_recursive(5.0), or passing a string/None. The guard is not isinstance(n, int).

Common situations: Whole-valued floats arriving from division or numpy operations; values read from JSON/config as floats; forgetting that bool is an int subclass (True returns 1 silently).

Related errors


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