TheAlgorithms/Python · error · ValueError

Discount rate cannot be negative

Error message

Discount rate cannot be negative

What it means

Raised by present_value() in financial/present_value.py when discount_rate < 0. The function discounts each cash flow by (1 + discount_rate) ** i; a negative rate would mean money gains value waiting, which the implementation refuses rather than silently computing. discount_rate = 0 is accepted and returns the plain sum.

Source

Thrown at financial/present_value.py:30

def present_value(discount_rate: float, cash_flows: list[float]) -> float:
    """
    >>> present_value(0.13, [10, 20.70, -293, 297])
    4.69
    >>> present_value(0.07, [-109129.39, 30923.23, 15098.93, 29734,39])
    -42739.63
    >>> present_value(0.07, [109129.39, 30923.23, 15098.93, 29734,39])
    175519.15
    >>> present_value(-1, [109129.39, 30923.23, 15098.93, 29734,39])
    Traceback (most recent call last):
        ...
    ValueError: Discount rate cannot be negative
    >>> present_value(0.03, [])
    Traceback (most recent call last):
        ...
    ValueError: Cash flows list cannot be empty
    """
    if discount_rate < 0:
        raise ValueError("Discount rate cannot be negative")
    if not cash_flows:
        raise ValueError("Cash flows list cannot be empty")
    present_value = sum(
        cash_flow / ((1 + discount_rate) ** i) for i, cash_flow in enumerate(cash_flows)
    )
    return round(present_value, ndigits=2)


if __name__ == "__main__":
    import doctest

    doctest.testmod()

View on GitHub (pinned to f5988cc097)

Solutions

  1. Pass a discount_rate >= 0 (0 is valid and returns the undiscounted sum).
  2. If negative rates are genuinely needed (EUR/CHF regimes), implement the discounting manually instead of using this function.
  3. Sanitize market-derived rates at the boundary: validate sign once where data enters your program.

Example fix

# before
present_value(market_rate, flows)  # market_rate == -0.002

# after
if market_rate < 0:
    pv = sum(flows)  # or custom negative-rate discounting
else:
    pv = present_value(market_rate, flows)
Defensive patterns

Strategy: validation

Validate before calling

if discount_rate < 0:
    raise ValueError(f'negative discount rate not supported: {discount_rate}')
present_value(discount_rate, cash_flows)

Try / catch

try:
    pv = present_value(r, flows)
except ValueError as exc:
    if 'Discount rate' in str(exc):
        pv = sum(flows)  # explicit fallback policy
    else:
        raise

Prevention

When it happens

Trigger: Calling present_value(rate, cash_flows) with a negative first argument, e.g. present_value(-1, [109129.39, 30923.23]). Only fires when years/rate checks upstream in your own code are absent — this is the function's first validation.

Common situations: Central-bank negative-rate eras feeding market data straight into the function, sign flips when converting from yield conventions, or debugging with -1 sentinels. Note: the module's own docstring example uses 0.07 for the happy path, so doctest runs never cover negative-rate paths.

Related errors


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