TheAlgorithms/Python · error · ValueError

nominal_annual_interest_rate_percentage must be >= 0

Error message

nominal_annual_interest_rate_percentage must be >= 0

What it means

Raised by compound_interest() in financial/interest.py when nominal_annual_interest_rate_percentage < 0. The parameter is expected as a decimal fraction per period (0.05 for 5%, per the doctest compound_interest(10000.0, 0.05, 3) => 1576.25); negative rates are rejected, and (1 + rate)**n would still be computable but is outside the modeled contract. It is the second check, after periods.

Source

Thrown at financial/interest.py:70

    >>> compound_interest(0.5, 0.05, 3)
    0.07881250000000006
    >>> compound_interest(10000.0, 0.06, -4)
    Traceback (most recent call last):
        ...
    ValueError: number_of_compounding_periods must be > 0
    >>> compound_interest(10000.0, -3.5, 3.0)
    Traceback (most recent call last):
        ...
    ValueError: nominal_annual_interest_rate_percentage must be >= 0
    >>> compound_interest(-5500.0, 0.01, 5)
    Traceback (most recent call last):
        ...
    ValueError: principal must be > 0
    """
    if number_of_compounding_periods <= 0:
        raise ValueError("number_of_compounding_periods must be > 0")
    if nominal_annual_interest_rate_percentage < 0:
        raise ValueError("nominal_annual_interest_rate_percentage must be >= 0")
    if principal <= 0:
        raise ValueError("principal must be > 0")

    return principal * (
        (1 + nominal_annual_interest_rate_percentage) ** number_of_compounding_periods
        - 1
    )


def apr_interest(
    principal: float,
    nominal_annual_percentage_rate: float,
    number_of_years: float,
) -> float:
    """
    >>> apr_interest(10000.0, 0.05, 3)
    1618.223072263547
    >>> apr_interest(10000.0, 0.05, 1)

View on GitHub (pinned to f5988cc097)

Solutions

  1. Pass the rate as a non-negative decimal fraction (0.05 for 5% per period).
  2. Sanitize market data: strip unicode minus, then check sign before calling.
  3. Double-check the unit: this parameter is a per-period decimal, so 5% monthly compounding uses 0.05, not 5.

Example fix

# before
ci = compound_interest(10000.0, -3.5, 3.0)  # ValueError

# after
ci = compound_interest(10000.0, 0.05, 3.0)  # matches doctest: 1576.25...
Defensive patterns

Strategy: validation

Validate before calling

if nominal_annual_interest_rate_percentage < 0:
    raise InputError("rate must be >= 0 as a decimal fraction (0.05 for 5%)")

Type guard

def valid_rate(r) -> bool:
    return isinstance(r, (int, float)) and r >= 0

Try / catch

try:
    ci = compound_interest(principal, rate, periods)
except ValueError as exc:
    raise InputError(str(exc)) from exc

Prevention

When it happens

Trigger: compound_interest(10000.0, -3.5, 3.0); passing -0.05 from a sign-flipped discount computation; passing a percentage like -5 instead of -0.05 (the latter raises, the magnitude error does not — see tips).

Common situations: Sign errors when rates are stored as spreads (lend minus borrow); negative central-bank rates in market data feeds; unicode minus signs from scraped tables.

Related errors


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