use crate::ONE;
use rust_decimal::prelude::*;
pub fn apr(ear: Decimal, npery: Decimal) -> Decimal {
let nth_root = (ONE + ear).powd(ONE / npery);
npery * (nth_root - ONE)
}
pub fn ear(apr: Decimal, npery: Decimal) -> Decimal {
let nth_root = ONE + apr / npery;
nth_root.powd(npery) - ONE
}
#[cfg(test)]
mod tests {
#[cfg(not(feature = "std"))]
extern crate std;
use super::*;
use rust_decimal_macros::dec;
#[cfg(not(feature = "std"))]
use std::assert;
#[cfg(not(feature = "std"))]
use std::prelude::v1::*;
#[test]
fn test_apr() {
struct TestCase {
n: Decimal,
ear: Decimal,
expected: Decimal,
description: &'static str,
}
impl TestCase {
fn new(n: f64, ear: f64, expected: f64, description: &'static str) -> TestCase {
TestCase {
n: Decimal::from_f64(n).unwrap(),
ear: Decimal::from_f64(ear).unwrap(),
expected: Decimal::from_f64(expected).unwrap(),
description,
}
}
}
let test_cases = [
TestCase::new(
12.0,
0.05,
0.04889,
"Standard case with EAR of 0.05 and monthly compounding",
),
TestCase::new(12.0, 0.0, 0.0, "Zero EAR should result in zero APR"),
TestCase::new(12.0, 0.2, 0.18371, "High EAR of 0.2 with monthly compounding"),
];
for case in &test_cases {
let calculated_apr = apr(case.ear, case.n);
assert!(
(calculated_apr - case.expected).abs() < dec!(1e-5),
"Failed on case: {}. Expected {}, got {}",
case.description,
case.expected,
calculated_apr
);
}
}
#[test]
fn test_ear() {
struct TestCase {
n: Decimal,
apr: Decimal,
expected: Decimal,
description: &'static str,
}
impl TestCase {
fn new(n: f64, apr: f64, expected: f64, description: &'static str) -> TestCase {
TestCase {
n: Decimal::from_f64(n).unwrap(),
apr: Decimal::from_f64(apr).unwrap(),
expected: Decimal::from_f64(expected).unwrap(),
description,
}
}
}
let test_cases = [
TestCase::new(
12.0,
0.05,
0.05116,
"Standard case with APR of 0.05 and monthly compounding",
),
TestCase::new(12.0, 0.0, 0.0, "Zero APR should result in zero EAR"),
TestCase::new(12.0, 0.2, 0.21939, "High APR of 0.2 with monthly compounding"),
];
for case in &test_cases {
let calculated_ear = ear(case.apr, case.n);
assert!(
(calculated_ear - case.expected).abs() < dec!(1e-5),
"Failed on case: {}. Expected {}, got {}",
case.description,
case.expected,
calculated_ear
);
}
}
}