A Scala application that calculates compound interest using the formula: A = P(1 + r)^n
This project tries to apply functional programming principles in Scala 3 where applicable, including:
- Immutable data structures with case classes
- Tail-recursive calculations for efficiency
- Comprehensive error handling with Either monad
- Type-safe validation of inputs
- Calculate compound interest for any principal amount, interest rate, and time period
- Annual contributions: Model regular investment scenarios with additional principal contributions
- Support for monthly compounding simulations
- Command-line interface with flexible argument parsing
- Built-in examples demonstrating various calculation scenarios
- Robust error handling and input validation
- Year-by-year analysis with tabular output for contribution calculations
- Year 0 baseline showing initial investment state
- Scala 3.7.0
- SBT 1.10.11
- Java 11 or higher
- Clone this repository:
git clone <repository-url>
cd compoundInterestCalculator
- Compile the project:
sbt compile
The calculator supports single calculations and calculations with annual contributions:
# With default principal of $1000
sbt "run <interest_rate> <years>"
# With custom principal amount
sbt "run <interest_rate> <years> <principal>"
# Calculate with annual contributions added after interest is applied
sbt "run <interest_rate> <years> <principal> <annual_contribution>"
Single Calculations:
# Calculate 5% interest for 10 years on $1000 (default)
sbt "run 5.0 10"
# Calculate 7.5% interest for 20 years on $5000
sbt "run 7.5 20 5000"
# Calculate monthly compounding (0.5% per month for 60 months)
sbt "run 0.5 60 10000"
Calculations with Annual Contributions:
# Calculate 6% interest for 5 years, starting with $120, adding $100 each year
sbt "run 6.0 5 120 100"
# Investment scenario: 15% return for 3 years, $240 start, $360 annual contribution
sbt "run 15.0 3 240 360"
# Long-term savings: 7.5% interest, 10 years, $500 start + $200/year
sbt "run 7.5 10 500 200"
Calculations with contributions provide a detailed table showing:
- Year 0: Initial investment baseline
- Year-by-year final amounts after interest and contributions
- Interest earned each specific year on existing balance
- Cumulative contributions added over time
- Total interest earned to date
Contribution Logic:
- Apply compound interest to existing balance
- Add annual contribution after interest is applied
- This models real-world investment scenarios
The calculator includes a comprehensive example suite:
# Run all examples
sbt "runMain CompoundInterestCalculator" exampleUsage
This will demonstrate:
- Simple calculation ($1000 at 5% for 10 years)
- Higher interest rate ($5000 at 7.5% for 20 years)
- Monthly compounding simulation
- Error handling examples
sbt console
Then in the REPL:
import CompoundInterestCalculator._
// Direct calculation
val input = validateInput(1000.0, 5.0, 10)
input.map(calculate).map(formatResult).foreach(println)
// Run examples
exampleUsage()
sbt compile
- Compile the Scala source codesbt run
- Run with interactive prompts for argumentssbt "run <args>"
- Run with command-line argumentssbt clean
- Clean build artifactssbt console
- Start Scala REPL with project classpath
sbt test
- Run all tests (45 comprehensive test cases)sbt "testOnly *SuiteName*"
- Run specific test suitesbt testQuick
- Run only tests that failed or changed
sbt coverage test coverageReport
- Generate code coverage reportsbt sonarScan
- Run SonarQube analysis
sbt show name
- Show project namesbt show version
- Show project versionsbt show scalaVersion
- Show Scala versionsbt dependencyTree
- Show dependency tree
sbt "run -h"
orsbt "run --help"
- Show usage information, examples, and all available SBT commands
compoundInterestCalculator/
├── build.sbt # Project build configuration
├── project/
│ ├── build.properties # SBT version specification
│ └── plugins.sbt # SBT plugins (scoverage, sonar-scala)
├── src/
│ ├── main/
│ │ └── scala/
│ │ ├── CompoundInterestCalculator.scala # Main application logic
│ │ ├── Messages.scala # All text messages and templates
│ │ └── Build.scala # Version information
│ └── test/
│ └── scala/
│ └── CompoundInterestCalculatorTest.scala # Comprehensive test suite
├── target/
│ └── scala-3.7.0/
│ └── scoverage-report/ # Coverage reports (HTML/XML)
└── README.md # This file
The main application consists of:
- CalculationInput: Case class for validated input parameters
- CalculationResult: Case class for calculation results
- CalculationType: Enum for distinguishing single vs contribution calculations
- validateInput: Input validation with error handling
- calculate: Tail-recursive compound interest calculation
- calculateWithContributions: Calculate with annual principal contributions
- formatResult: Pretty-printing of single calculation results
- formatResultsWithContributions: Enhanced table for contribution scenarios
- parseArguments: Command-line argument parsing (supports 2-4 arguments)
- showHelp: Comprehensive help system with SBT commands
- exampleUsage: Demonstration examples
The compound interest formula used is:
A = P(1 + r)^n
Where:
- A = Final amount
- P = Principal (initial investment)
- r = Interest rate (as decimal, e.g., 5% = 0.05)
- n = Number of compounding periods
For monthly compounding:
- Divide annual rate by 12
- Multiply years by 12
For Calculations with Contributions:
Year N = (Previous Year Balance × (1 + r)) + Annual Contribution
Where each year:
1. Apply interest to existing balance
2. Add annual contribution
3. This becomes the base for next year's calculation
The calculator validates:
- Principal amount must be positive
- Interest rate cannot be negative
- Years/periods must be positive
- Annual contributions cannot be negative
- Command-line arguments must be valid numbers
Invalid inputs return descriptive error messages.
The project includes 45 comprehensive test cases with excellent coverage metrics:
- Valid inputs acceptance
- Negative/zero principal rejection
- Negative interest rate handling
- Invalid years validation
- Basic compound interest calculations
- Zero interest rate scenarios
- Single year calculations
- High interest rate handling
- Very small and large amounts
- Range calculations with multiple years
- Contribution calculations with corrected logic
- Year 0 baseline testing
- Interest-first, then contribution logic verification
- Single calculations (2-3 arguments)
- Contribution calculations (4 arguments)
- Help flag handling (
-h
,--help
) - Invalid argument types
- Input validation (positive values)
- Contribution validation (non-negative values)
- Wrong number of arguments
- Single calculation result formatting
- Contribution calculation table formatting
- Dollar sign and percentage formatting
- Year 0 display formatting
- Large year calculations (50+ years)
- Precision handling for floating point calculations
- Boundary value testing
# Run all tests
sbt test
# Generate coverage report
sbt coverage test coverageReport
# View coverage report (HTML)
open target/scala-3.7.0/scoverage-report/index.html
# Run SonarQube analysis
sbt sonarScan
The project uses ScalaCheck for property-based testing, validating:
- Mathematical properties of compound interest formula
- Monotonicity of calculations with increasing parameters
- Consistency and deterministic behavior
- Edge cases with generated test data
- Custom generators for realistic financial scenarios
- Scala 3.7.0 - Core language
- MUnit 1.0.0 - Modern testing framework
- ScalaCheck 1.17.0 - Property-based testing
- MUnit-ScalaCheck 1.0.0 - ScalaCheck integration for MUnit
- sbt-scoverage 2.0.12 - Code coverage analysis
- sbt-sonar 2.3.0 - SonarQube integration
The project is configured for comprehensive code quality analysis with SonarQube:
# Run SonarQube analysis (requires SonarQube server)
sbt sonarScan
# With custom SonarQube server
sbt -Dsonar.host.url=http://localhost:9000 sonarScan
Available Reports:
- HTML Coverage:
target/scala-3.7.0/scoverage-report/index.html
- XML Coverage:
target/scala-3.7.0/scoverage-report/scoverage.xml
- Cobertura Format:
target/scala-3.7.0/coverage-report/cobertura.xml
To create a standalone JAR:
sbt package
The JAR will be created in target/scala-3.7.0/
0ldmanc0d1ing