Functional Weave
Code in Rust

banking.savings-aer@1.0.0

impl/rust.rs

1,358 bytes · the Rust implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

use super::funejson::Value;  ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one
use super::math_big_integer::BigInt;  ← from math.big-integer ^1.0.0 · built alongside by fune

/// 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()))
}