TheAlgorithms/Python · error · ValueError

double_factorial_iterative() only accepts integral values

Error message

double_factorial_iterative() only accepts integral values

What it means

Raised by double_factorial_iterative() in maths/double_factorial.py when num is not an int. The iterative loop for i in range(num, 0, -2) requires an integer to build the range, so float inputs like 0.1 are rejected with ValueError up front rather than producing a confusing range TypeError.

Source

Thrown at maths/double_factorial.py:48

    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):
        ...
    ValueError: double_factorial_iterative() only accepts integral values
    >>> double_factorial_iterative(-1)
    Traceback (most recent call last):
        ...
    ValueError: double_factorial_iterative() not defined for negative values
    """
    if not isinstance(num, int):
        raise ValueError("double_factorial_iterative() only accepts integral values")
    if num < 0:
        raise ValueError("double_factorial_iterative() not defined for negative values")
    value = 1
    for i in range(num, 0, -2):
        value *= i
    return value


if __name__ == "__main__":
    import doctest

    doctest.testmod()

View on GitHub (pinned to f5988cc097)

Solutions

  1. Cast whole floats: double_factorial_iterative(int(num)) when num == int(num).
  2. Prefer math.prod(range(int(num), 0, -2)) for tolerant/numpy-friendly inputs.
  3. Keep values as ints through the pipeline; use // instead of / for integer division.

Example fix

# before
double_factorial_iterative(14 / 2)  # ValueError (7.0 is a float)

# after
double_factorial_iterative(14 // 2)  # int 7, returns 105
Defensive patterns

Strategy: type-guard

Validate before calling

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

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_iterative(num)
except ValueError as e:
    if 'integral values' in str(e):
        r = double_factorial_iterative(int(num))
    else:
        raise

Prevention

When it happens

Trigger: Calling double_factorial_iterative(0.1), double_factorial_iterative(7.0), or passing any non-int. The guard is not isinstance(num, int).

Common situations: Floats from arithmetic or deserialization (7.0 instead of 7); numpy scalars that are not plain int on some platforms; passing the result of a division like 14/2.

Related errors


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