Skip to content

BUG: take the fv result dtype from all inputs, not just rate - #167

Closed
kritagyadubey wants to merge 1 commit into
numpy:mainfrom
kritagyadubey:gh-166-integer-rate-dtype
Closed

kritagyadubey wants to merge 1 commit into
numpy:mainfrom
kritagyadubey:gh-166-integer-rate-dtype

Conversation

@kritagyadubey

Copy link
Copy Markdown

Fixes #166

Problem

fv sizes and types its output buffer from rate alone (np.empty_like(rate)), so an integer rate gives an integer buffer and the float result is truncated toward zero: npf.fv(0, 12, -100.5, -1000.25) returns 2206 instead of 2206.25.

ipmt and ppmt are affected through _rbl, which calls fv. The remaining-balance array comes back integer typed, and _value_like cannot store NaN in it, so they raise ValueError: cannot convert float NaN to integer before any arithmetic happens:

>>> npf.ipmt(0, 1, 12, 1200)
ValueError: cannot convert float NaN to integer
>>> npf.ppmt(0, 1, 12, 1200)
ValueError: cannot convert float NaN to integer

This only takes an extra float (0.0 instead of 0) to avoid, which is easy to miss for the common case of a 0% loan.

Change

Derive the dtype from all the inputs when allocating the fv output buffer:

fv_array = np.empty_like(rate, dtype=np.result_type(rate, nper, pmt, pv, 1.0))

This matches the promotion the rest of the module already gets from arithmetic. pmt, ppmt and pv all return float64 for the same integer inputs, so fv was the only function affected. Inputs that are already float are unchanged, since result_type treats the 1.0 literal as a weak scalar, and Decimal inputs still produce an object array.

Testing

Run on Python 3.14.7, numpy 2.5.4, Windows:

  • spin test -- --doctest-modules: 122 passed, including three new regression tests (TestFv::test_gh_166, TestIpmt::test_gh_166, TestPpmt::test_gh_166). All three fail without the change to _financial.py.
  • ruff check numpy_financial/ benchmarks/, mypy --no-incremental . and pyright (the checks in spin lint): no findings.

An integer rate gave an integer output buffer, so fractional results
were truncated and ipmt/ppmt raised ValueError when they tried to
store NaN in the remaining-balance array.
@kritagyadubey kritagyadubey closed this by deleting the head repository Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

An integer rate truncates fv to an integer and makes ipmt/ppmt raise

1 participant