use super::funejson::Value; use super::math_big_integer::BigInt; /// The AER of a gross rate paid `payments_per_year` times a year: /// (1 + i / n)^n − 1, per the UK Finance / BSA AER Practice Note formula (d), /// rounded half-up to two decimal places of a percent (a whole basis point). /// /// With i = b / 10000 and D = 10000 × n the exact value in basis points is /// 10000 × ((D + b)^n − D^n) / D^n, computed in integers and rounded once. /// /// # Panics /// Panics on a rate or frequency out of range. pub fn savings_aer(gross_rate_basis_points: i64, payments_per_year: i64) -> i64 { let b = gross_rate_basis_points; if b < 0 || b > 100000 { panic!("grossRateBasisPoints must be between 0 and 100000, received {}", b); } let n = payments_per_year; if n < 1 || n > 365 { panic!("paymentsPerYear must be between 1 and 365, received {}", n); } let d = BigInt::from_i64(10000 * n); let whole = d.pow(n as u64); let numerator = BigInt::from_i64(10000).mul(&d.add(&BigInt::from_i64(b)).pow(n as u64).sub(&whole)); // Half-up for a non-negative fraction: floor((2N + M) / 2M). let two = BigInt::from_i64(2); two.mul(&numerator).add(&whole).div(&two.mul(&whole)).to_i64() } pub fn fune_vector(args: &[Value]) -> Value { Value::Int(savings_aer(args[0].as_i64(), args[1].as_i64())) }