module.exports = { slug: "future-value-of-annuity", title: "Future value of an annuity", deck_category: "finance", description: "Computes the future value of a series of equal periodic payments, either an ordinary annuity or an annuity due.", inputs: [ { name: "payment", type: "number", unit: "currency units", required: true, description: "Equal payment made each period", min: 0 }, { name: "annual_rate_percent", type: "number", unit: "%", required: true, description: "Nominal annual rate, compounded once per payment period", min: 0 }, { name: "periods", type: "integer", required: true, description: "Number of payment periods", min: 1 }, { name: "is_annuity_due", type: "boolean", required: true, description: "True if payments occur at the start of each period (annuity due); false for the end (ordinary annuity)" } ], outputs: [ { name: "future_value", unit: "currency units", description: "Value of the annuity at the end of the last period" } ], steps: [ "Convert the annual rate to a decimal per period: i = annual_rate_percent / 100 (one compounding per payment period).", "Ordinary annuity future value: FV_ordinary = payment * (((1 + i)^periods - 1) / i), or payment * periods if i = 0.", "If is_annuity_due is true, future_value = FV_ordinary * (1 + i); otherwise future_value = FV_ordinary.", "Round future_value to 2 decimals (money to cents)." ], constants: [], sources: [ { kind: "edition_page", value: "Brealey, Myers, Allen, Principles of Corporate Finance, 13th ed., Chapter 3, section 3-2 (Future Value of an Annuity)", title: "Principles of Corporate Finance", publisher: "McGraw-Hill", retrieved_utc: "2026-09-30T19:31:29Z", note: "FV ordinary annuity = PMT*(((1+i)^n - 1)/i); annuity due multiplies by (1+i)" } ], disclaimer: null, questionText(inputs) { const kind = inputs.is_annuity_due ? "annuity due (payments at the start of each period)" : "ordinary annuity (payments at the end of each period)"; return `What is the future value of a $${inputs.payment} ${kind} paid ${inputs.periods} times at ${inputs.annual_rate_percent}% interest per period?`; }, run(inputs) { const { payment, annual_rate_percent, periods, is_annuity_due } = inputs; if (typeof payment !== "number" || payment < 0) throw new Error("payment must be a non-negative number"); if (typeof annual_rate_percent !== "number" || annual_rate_percent < 0) throw new Error("annual_rate_percent must be a non-negative number"); if (!Number.isInteger(periods) || periods <= 0) throw new Error("periods must be a positive integer"); if (typeof is_annuity_due !== "boolean") throw new Error("is_annuity_due must be a boolean"); const i = annual_rate_percent / 100; let fvOrdinary; if (i === 0) { fvOrdinary = payment * periods; } else { fvOrdinary = payment * ((Math.pow(1 + i, periods) - 1) / i); } const future_value = Math.round((is_annuity_due ? fvOrdinary * (1 + i) : fvOrdinary) * 100) / 100; const fmt = (n) => n.toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ","); return { answer: `$${fmt(future_value)}`, values: { future_value } }; }, examples: [ { name: "worked example", inputs: { payment: 1000, annual_rate_percent: 5, periods: 10, is_annuity_due: false }, expected: { answer: "$12,577.89" }, check: "hand computation: FV = 1000*((1.05^10 - 1)/0.05) = 1000*(1.628894.../0.05) = 1000*12.577893... = 12577.89" }, { name: "test vector: annuity due", inputs: { payment: 1000, annual_rate_percent: 5, periods: 10, is_annuity_due: true }, expected: { answer: "$13,206.79" }, check: "hand computation: ordinary FV = 12577.8925..., due FV = 12577.8925*1.05 = 13206.7871..., rounds to 13206.79" } ] };