use crate::FinPrimError;
use crate::FloatLike;
pub fn pct_change<T: FloatLike>(beginning_value: T, ending_value: T) -> Result<T, FinPrimError<T>> {
if beginning_value.is_zero() {
return Err(FinPrimError::DivideByZero);
}
Ok((ending_value - beginning_value) / beginning_value.abs()) }
pub fn apply_pct_change<T: FloatLike>(value: T, pct_change: T) -> T {
pct_change * value.abs() + value
}
#[cfg(test)]
mod tests {
use super::*;
struct TestCase {
beginning_value: f64,
ending_value: f64,
pct_change: f64,
}
impl TestCase {
fn new(beginning_value: f64, ending_value: f64, pct_change: f64) -> Self {
TestCase {
beginning_value,
ending_value,
pct_change,
}
}
}
#[test]
fn test_pct_change_and_apply_pct_change() {
let cases = [
TestCase::new(1000.0, 1500.0, 0.5), TestCase::new(1000.0, 500.0, -0.5), TestCase::new(1000.0, 1000.0, 0.0), TestCase::new(1000.0, -1500.0, -2.5), TestCase::new(-1000.0, 1500.0, 2.5), ];
for case in &cases {
let pct_change_result = pct_change(case.beginning_value, case.ending_value);
assert_eq!(pct_change_result, Ok(case.pct_change));
let apply_pct_change_result = apply_pct_change(case.beginning_value, case.pct_change);
assert_eq!(apply_pct_change_result, case.ending_value);
}
let result_zero = pct_change(0.0, 1000.0).unwrap_or(0.0);
assert_eq!(result_zero, 0.0);
}
}