use crate::FloatLike;
pub fn pv_prime_r<T: FloatLike>(rate: T, n: T, cash_flow: T) -> T {
-cash_flow * n / (rate + T::one()).powf(n + T::one())
}
pub fn npv_prime_r<T: FloatLike>(rate: T, cash_flows: &[T]) -> T {
let mut powf_acc = T::one() + rate;
let mut npv_prime = T::zero();
for (t, &cf) in cash_flows.iter().enumerate() {
npv_prime += -cf * T::from_usize(t) / powf_acc;
powf_acc *= T::one() + rate;
}
npv_prime
}
pub fn pv_prime2_r<T: FloatLike>(rate: T, n: T, cash_flow: T) -> T {
cash_flow * n * (n + T::one()) / (rate + T::one()).powf(n + T::two())
}
pub fn npv_prime2_r<T: FloatLike>(rate: T, cash_flows: &[T]) -> T {
let mut powf_acc = (T::one() + rate) * (T::one() + rate);
let mut npv_prime2 = T::zero();
for (t, &cf) in cash_flows.iter().enumerate() {
let t = T::from_usize(t);
npv_prime2 += cf * t * (t + T::one()) / powf_acc;
powf_acc *= T::one() + rate;
}
npv_prime2
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(not(feature = "std"))]
extern crate std;
#[cfg(not(feature = "std"))]
use std::{assert, vec};
#[test]
fn test_pv_prime() {
let rate = 0.05;
let n = 5.0;
let cash_flow = 1000.0;
let result = pv_prime_r(rate, n, cash_flow);
let expected: f64 = -3731.07698;
assert!(
(result - expected).abs() < 1e-5,
"Failed on case: {}. Expected: {}, Result: {}",
"Rate of 5%, 5th period, cash flow of $1000",
expected,
result
);
}
#[test]
fn test_pv_double_prime() {
let rate = 0.05;
let n = 5.0;
let cash_flow = 1000.0;
let result = pv_prime2_r(rate, n, cash_flow);
let expected: f64 = 21320.43990;
assert!(
(result - expected).abs() < 1e-5,
"Failed on case: {}. Expected: {}, Result: {}",
"Rate of 5%, 5th period, cash flow of $1000",
expected,
result
);
}
#[test]
fn test_npv_prime() {
let rate = 0.05;
let cash_flows = vec![1000.0, 2000.0, 3000.0];
let expected = cash_flows
.iter()
.enumerate()
.map(|(t, &cf)| pv_prime_r(rate, t as f64, cf))
.sum::<f64>();
let result = npv_prime_r(rate, &cash_flows);
assert!(
(result - expected).abs() < 1e-5,
"Failed on case: {}. Expected: {}, Result: {}",
"Rate of 5%, cash flows of $1000, $2000, $3000",
expected,
result
);
}
#[test]
fn test_npv_double_prime() {
let rate = 0.05;
let cash_flows = vec![1000.0, 2000.0, 3000.0];
let expected = cash_flows
.iter()
.enumerate()
.map(|(t, &cf)| pv_prime2_r(rate, t as f64, cf))
.sum::<f64>();
let result = npv_prime2_r(rate, &cash_flows);
assert!(
(result - expected).abs() < 1e-5,
"Failed on case: {}. Expected: {}, Result: {}",
"Rate of 5%, cash flows of $1000, $2000, $3000",
expected,
result
);
}
}