BusinessMath Quarterly Series
6 min read
Part 1 of 12-Week BusinessMath Series
Financial calculations are everywhere in business: retirement planning, loan amortization, investment analysis, revenue forecasting. But implementing these correctly requires understanding compound interest, time series data structures, and numerical precision—and getting any of it wrong can cost real money.
BusinessMath is a library that handles the complexity while giving you confidence in the results. Calculations work across different numeric types (Double, Float) without rewriting code. And the API is ergonomic and clear enough that you can understand it six months from now or pick it up and work with it day-to-day.
BusinessMath makes complex calculations simple. Here’s how to get started:
Add BusinessMath to your Package.swift:
dependencies: [
.package(url: "https://github.com/jpurnell/BusinessMath.git", from: "2.0.0")
]
Then import it:
import BusinessMath
import BusinessMath
// Present value: What's $110,000 in 1 year worth today at 10% rate?
let pv = presentValue(
futureValue: 110_000,
rate: 0.10,
periods: 1
)
print("Present value: \(pv.currency())")
// Output: Present value: $100,000.00
// Future value: What will $100K grow to in 5 years at 8%?
let fv = futureValue(
presentValue: 100_000,
rate: 0.08,
periods: 5
)
print("Future value: \(fv.currency())")
// Output: Future value: $146,932.81
BusinessMath provides type-safe temporal identifiers:
// Create periods at different granularities
let jan2025 = Period.month(year: 2025, month: 1)
let q1_2025 = Period.quarter(year: 2025, quarter: 1)
let fy2025 = Period.year(2025)
// Period arithmetic
let feb2025 = jan2025 + 1 // Next month
let yearRange = jan2025...jan2025 + 11 // Full year
// Subdivision
let quarters = fy2025.quarters() // [Q1, Q2, Q3, Q4]
let months = q1_2025.months() // [Jan, Feb, Mar]
Associate values with time periods for analysis:
let periods = [
Period.month(year: 2025, month: 1),
Period.month(year: 2025, month: 2),
Period.month(year: 2025, month: 3)
]
let revenue: [Double] = [100_000, 120_000, 115_000]
let ts = TimeSeries(periods: periods, values: revenue)
// Access values by period
if let janRevenue = ts[periods[0]] {
print("January: \(janRevenue.currency())")
}
// Iterate over values
for (period, value) in zip(periods, ts) {
print("\(period.label): \(ts[period]!.currency())")
}
Evaluate projects with NPV and IRR:
// Cash flows: initial investment, then returns over 5 years
let cashFlows = [-250_000.0, 100_000, 150_000, 200_000, 250_000, 300_000]
// Net Present Value at 10% discount rate
let npvValue = npv(discountRate: 0.10, cashFlows: cashFlows)
print("NPV: $\(npvValue.formatted(.number.precision(.fractionLength(2))))")
// Output: NPV: $472,169.05 (positive NPV → good investment!)
// Internal Rate of Return
let irrValue = try irr(cashFlows: cashFlows)
print("IRR: \(irrValue.formatted(.percent.precision(.fractionLength(2))))")
// Output: IRR: 56.77% (impressive return!)
BusinessMath is built on three core principles:
Periods use Swift enums to prevent mixing incompatible time granularities. You can’t accidentally add a month to a day—the compiler catches it.
Financial functions work with any numeric type conforming to Real from swift-numerics:
// Works with Double
let pvDouble = presentValue(futureValue: 1000.0, rate: 0.05, periods: 10.0)
// Works with Float
let pvFloat: Float = presentValue(futureValue: 1000.0, rate: 0.05, periods: 10.0)
Functions compose naturally. Time series can be transformed, aggregated, and analyzed using simple and ergonomic Swift patterns.
Copy to an Xcode playground and experiment:
import BusinessMath
// Present value: What's $110,000 in 1 year worth today at 10% rate?
let pv = presentValue(
futureValue: 110_000,
rate: 0.10,
periods: 1
)
print("Present value: \(pv.currency())")
// Output: Present value: $100,000.00
// Future value: What will $100K grow to in 5 years at 8%?
let fv = futureValue(
presentValue: 100_000,
rate: 0.08,
periods: 5
)
print("Future value: \(fv.currency())")
// Output: Future value: $146,932.81
// Create periods at different granularities
let jan2025 = Period.month(year: 2025, month: 1)
let q1_2025 = Period.quarter(year: 2025, quarter: 1)
let fy2025 = Period.year(2025)
// Period arithmetic
let feb2025 = jan2025 + 1 // Next month
let yearRange = jan2025...jan2025 + 11 // Full year
// Subdivision
let quarters = fy2025.quarters() // [Q1, Q2, Q3, Q4]
let months = q1_2025.months() // [Jan, Feb, Mar]
let periods = [
Period.month(year: 2025, month: 1),
Period.month(year: 2025, month: 2),
Period.month(year: 2025, month: 3)
]
let revenue: [Double] = [100_000, 120_000, 115_000]
let ts = TimeSeries(periods: periods, values: revenue)
// Access values by period
if let janRevenue = ts[periods[0]] {
print("January: \(janRevenue.currency())")
}
for (period, value) in zip(periods, ts) {
print("\(period.label): \(ts[period]!.currency())")
}
// Cash flows: initial investment, then returns over 5 years
let cashFlows = [-250_000.0, 100_000, 150_000, 200_000, 250_000, 300_000]
// Net Present Value at 10% discount rate
let npvValue = npv(discountRate: 0.10, cashFlows: cashFlows)
print("NPV: \(npvValue.currency())")
// Output: NPV: $472,168.75 (positive NPV → good investment!)
// Internal Rate of Return
let irrValue = try irr(cashFlows: cashFlows)
print("IRR: \(irrValue.percent())")
// Output: IRR: 56.72% (impressive return!)
// Works with Double
let pvDouble = presentValue(futureValue: 1000.0, rate: 0.05, periods: 10)
// Works with Float
let pvFloat: Float = presentValue(futureValue: 1000.0, rate: 0.05, periods: 10)
→ Full API Reference: BusinessMath Docs – Getting Started
Modifications to try:
Financial calculations power critical business decisions. A financial advisor uses PV/FV to calculate retirement contributions. A CFO uses NPV to evaluate capital projects. A business analyst uses time series to forecast revenue.
Getting these calculations right matters. A 0.1% error in IRR on a $10M project translates to $10,000 in misallocated capital. BusinessMath’s rigorous testing (200+ tests) and documentation ensure you can trust the results.
When we started the BusinessMath project, the first question was: “What does production quality mean?” We defined it explicitly from day one: comprehensive tests, full documentation, zero compiler warnings.
That clarity determined every decision afterward. AI doesn’t inherently produce production-quality code—it amplifies your standards. Set them high initially, and AI helps you meet them. Set them low, and AI happily generates technical debt.
The first function (present value) had one test. By the end, we had 247 tests and 100% documentation coverage. The standards compounded.
Lesson: Define “production quality” for your next project before writing any code. Be explicit. Write it down. Reference it in every AI prompt.
Related Methodology: Test-First Development with AI (Tuesday’s post)
Coming up next: Time Series Foundation (Wednesday) - Deep dive into periods and temporal data structures
This week’s capstone: Case Study #1: Retirement Planning Calculator (Friday) - Combines TVM and statistical distributions to answer “How much do I need to save?”
Series Progress:
Tagged with: businessmath, swift, getting-started, tvm, time-series