Skip to content

# Issue 3: [BUG] PMT/FV/PV/NPER silently ignore the 5th "type" argument (annuity-due) #213

Description

@Sh-TB

Issue 3: [BUG] PMT/FV/PV/NPER silently ignore the 5th "type" argument (annuity-due)

Classification

Bug

Severity

Medium — wrong result only when 5th arg is used, but silent

File

Core/Formula/FormulaEvaluator.Functions.cs:1118-1149

Root Cause

EvalPmt, EvalFv, EvalPv, and EvalNper only read args[0..3]. The 5th Excel argument type (0 = payment at end of period [default], 1 = payment at beginning) is never read or applied:

private static FormulaResult? EvalPmt(List<object> args)
{
    if (args.Count < 3) return null;
    double rate = args[0] is FormulaResult r ? r.AsNumber() : 0,
           nper = args[1] is FormulaResult r2 ? r2.AsNumber() : 0,
           pv = args[2] is FormulaResult r3 ? r3.AsNumber() : 0;
    var fv = args.Count > 3 && args[3] is FormulaResult r4 ? r4.AsNumber() : 0;
    // ← args[4] (type) is NEVER read
    if (rate == 0) return FR(-(pv + fv) / nper);
    return FR(-(rate * (pv * Math.Pow(1 + rate, nper) + fv) / (Math.Pow(1 + rate, nper) - 1)));
    // ← no (1+rate) multiplier for type=1
}

The same pattern applies to EvalFv (line 1126), EvalPv (line 1134), and EvalNper (line 1142) — all read up to args[3] and none read args[4].

Repro (PoC)

=PMT(0.05/12, 12, 1000, 0, 0)   → ordinary annuity
=PMT(0.05/12, 12, 1000, 0, 1)   → annuity-due (payment at beginning)

Expected vs Actual

type=0 type=1
Expected (Excel) -85.607465 -85.251971 (different!)
Actual (this code) -85.607482 -85.607482 (identical)

Runtime Verification

Compiled and executed with .NET SDK 8.0.423. Both type=0 and type=1 return -85.607482, confirming the type argument is silently ignored.

Why maintainer accepts this

The functions are registered in the dispatch table and accept 4 arguments — they are "implemented" but incomplete. If type=1 were unsupported, the function should return #N/A or #VALUE!, not silently return the wrong (ordinary-annuity) result. Excel documentation: PMT function.

Fix

Read args[4] (default 0) and apply the standard annuity-due adjustment (multiply by (1 + rate) when type == 1) per the standard financial formula.

Classification

Bug

Severity

Medium — wrong result only when 5th arg is used, but silent

File

Core/Formula/FormulaEvaluator.Functions.cs:1118-1149

Root Cause

EvalPmt, EvalFv, EvalPv, and EvalNper only read args[0..3]. The 5th Excel argument type (0 = payment at end of period [default], 1 = payment at beginning) is never read or applied:

private static FormulaResult? EvalPmt(List<object> args)
{
    if (args.Count < 3) return null;
    double rate = args[0] is FormulaResult r ? r.AsNumber() : 0,
           nper = args[1] is FormulaResult r2 ? r2.AsNumber() : 0,
           pv = args[2] is FormulaResult r3 ? r3.AsNumber() : 0;
    var fv = args.Count > 3 && args[3] is FormulaResult r4 ? r4.AsNumber() : 0;
    // ← args[4] (type) is NEVER read
    if (rate == 0) return FR(-(pv + fv) / nper);
    return FR(-(rate * (pv * Math.Pow(1 + rate, nper) + fv) / (Math.Pow(1 + rate, nper) - 1)));
    // ← no (1+rate) multiplier for type=1
}

The same pattern applies to EvalFv (line 1126), EvalPv (line 1134), and EvalNper (line 1142) — all read up to args[3] and none read args[4].

Repro (PoC)

=PMT(0.05/12, 12, 1000, 0, 0)   → ordinary annuity
=PMT(0.05/12, 12, 1000, 0, 1)   → annuity-due (payment at beginning)

Expected vs Actual

type=0 type=1
Expected (Excel) -85.607465 -85.251971 (different!)
Actual (this code) -85.607482 -85.607482 (identical)

Runtime Verification

Compiled and executed with .NET SDK 8.0.423. Both type=0 and type=1 return -85.607482, confirming the type argument is silently ignored.

Why maintainer accepts this

The functions are registered in the dispatch table and accept 4 arguments — they are "implemented" but incomplete. If type=1 were unsupported, the function should return #N/A or #VALUE!, not silently return the wrong (ordinary-annuity) result. Excel documentation: PMT function.

Fix

Read args[4] (default 0) and apply the standard annuity-due adjustment (multiply by (1 + rate) when type == 1) per the standard financial formula.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions