TheAlgorithms/Python · error · ValueError

daily_interest_rate must be >= 0

Error message

daily_interest_rate must be >= 0

What it means

Raised by simple_interest() in financial/interest.py when daily_interest_rate < 0. Zero rate is allowed (interest is then 0), but a negative rate would produce negative interest that the doctest contract does not model. It is the second check, so days_between_payments is already valid when it fires.

Source

Thrown at financial/interest.py:36

    >>> simple_interest(5500.0, 0.01, 100)
    5500.0
    >>> simple_interest(10000.0, -0.06, 3)
    Traceback (most recent call last):
        ...
    ValueError: daily_interest_rate must be >= 0
    >>> simple_interest(-10000.0, 0.06, 3)
    Traceback (most recent call last):
        ...
    ValueError: principal must be > 0
    >>> simple_interest(5500.0, 0.01, -5)
    Traceback (most recent call last):
        ...
    ValueError: days_between_payments must be > 0
    """
    if days_between_payments <= 0:
        raise ValueError("days_between_payments must be > 0")
    if daily_interest_rate < 0:
        raise ValueError("daily_interest_rate must be >= 0")
    if principal <= 0:
        raise ValueError("principal must be > 0")
    return principal * daily_interest_rate * days_between_payments


def compound_interest(
    principal: float,
    nominal_annual_interest_rate_percentage: float,
    number_of_compounding_periods: float,
) -> float:
    """
    >>> compound_interest(10000.0, 0.05, 3)
    1576.2500000000014
    >>> compound_interest(10000.0, 0.05, 1)
    500.00000000000045
    >>> compound_interest(0.5, 0.05, 3)
    0.07881250000000006
    >>> compound_interest(10000.0, 0.06, -4)

View on GitHub (pinned to f5988cc097)

Solutions

  1. Pass the daily rate as a non-negative decimal fraction (0.0005 for 0.05%/day).
  2. If converting from an annual percentage, divide consistently and clamp at 0 only after confirming negatives are data errors.
  3. Validate rate >= 0 in your ingestion layer with a clear error naming the field.

Example fix

# before
si = simple_interest(10000.0, -0.06, 3)  # ValueError

# after
si = simple_interest(10000.0, 0.0006, 3)
Defensive patterns

Strategy: validation

Validate before calling

if daily_interest_rate < 0:
    raise InputError("daily rate must be >= 0 as a decimal (0.0005 for 0.05%/day)")

Type guard

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

Try / catch

try:
    si = simple_interest(principal, daily_rate, days)
except ValueError as exc:
    raise InputError(str(exc)) from exc

Prevention

When it happens

Trigger: simple_interest(10000.0, -0.06, 3); rates computed as (new_rate - old_rate) deltas; percent-to-decimal conversion bugs that introduce a sign.

Common situations: Passing 6 instead of 0.06 combined with a sign flip from discount arithmetic; negative promotional rates in product data; scraping a rate field that includes a unicode minus.

Related errors


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