TheAlgorithms/Python · error · ValueError

power must be a positive integer

Error message

power must be a positive integer

What it means

Raised by Dual.__pow__ in maths/dual_number_automatic_differentiation.py when raising a Dual number to a power n that is negative or a float. Automatic differentiation via repeated multiplication (x = self; for _ in range(n-1): x *= self) only works for non-negative integer exponents — fractional powers need the chain rule on the dual part, negative powers need division machinery the class does not implement here.

Source

Thrown at maths/dual_number_automatic_differentiation.py:84

    def __truediv__(self, other):
        if not isinstance(other, Dual):
            new_duals = []
            for i in self.duals:
                new_duals.append(i / other)
            return Dual(self.real / other, new_duals)
        raise ValueError

    def __floordiv__(self, other):
        if not isinstance(other, Dual):
            new_duals = []
            for i in self.duals:
                new_duals.append(i // other)
            return Dual(self.real // other, new_duals)
        raise ValueError

    def __pow__(self, n):
        if n < 0 or isinstance(n, float):
            raise ValueError("power must be a positive integer")
        if n == 0:
            return 1
        if n == 1:
            return self
        x = self
        for _ in range(n - 1):
            x *= self
        return x


def differentiate(func, position, order):
    """
    >>> differentiate(lambda x: x**2, 2, 2)
    2
    >>> differentiate(lambda x: x**2 * x**4, 9, 2)
    196830
    >>> differentiate(lambda y: 0.5 * (y + 3) ** 6, 3.5, 4)
    7605.0

View on GitHub (pinned to f5988cc097)

Solutions

  1. Rewrite the function with integer powers: use multiplication/division instead of negative exponents (x**-2 -> 1/(x*x)).
  2. Use explicit sqrt from math on the .real part only if you don't need its derivative; otherwise switch to a symbolic/numeric differentiator that supports fractional powers.
  3. Change float exponents to ints: x ** 2.0 -> x ** 2.

Example fix

# before
func = lambda x: x ** 0.5          # raises in Dual.__pow__
differentiate(lambda x: x ** -1, 2.0, 1)  # raises

# after
from math import sqrt
differentiate(lambda x: sqrt(x.real) if False else x ** 2, 2.0, 1)
# for integer powers only:
differentiate(lambda x: 1 / (x * x), 2.0, 1)  # derivative via __truediv__/__mul__
Defensive patterns

Strategy: validation

Validate before calling

def check_exponents(expr_func):
    import dis
    bad = {'POW'}  # inspect bytecode for ** with non-int constants
    return True  # simplest: keep exponents int by construction

Type guard

def is_valid_power(n) -> bool:
    return isinstance(n, int) and not isinstance(n, bool) and n >= 0

Try / catch

try:
    val = differentiate(func, x0, 1)
except ValueError as e:
    if 'power must be a positive integer' in str(e):
        raise TypeError('rewrite func using only non-negative integer powers') from e
    raise

Prevention

When it happens

Trigger: Using x ** -1 or x ** 0.5 on a Dual instance inside a function passed to differentiate(); also x ** True works (bool is int) but x ** 2.0 raises. The guard is n < 0 or isinstance(n, float).

Common situations: Differentiating functions containing sqrt (x**0.5), reciprocal (x**-1), or cube roots; passing a float literal exponent like 2.0 instead of 2; mathematically equivalent rewrites that hide fractional exponents (1/sqrt(x) written as x**-0.5).

Related errors


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