rust_finprim/derivatives/
pv.rs1use crate::FloatLike;
2
3pub fn pv_prime_r<T: FloatLike>(rate: T, n: T, cash_flow: T) -> T {
16 -cash_flow * n / (rate + T::one()).powf(n + T::one())
17}
18
19pub fn npv_prime_r<T: FloatLike>(rate: T, cash_flows: &[T]) -> T {
31 let mut powf_acc = T::one() + rate;
34 let mut npv_prime = T::zero();
35 for (t, &cf) in cash_flows.iter().enumerate() {
36 npv_prime += -cf * T::from_usize(t) / powf_acc;
37 powf_acc *= T::one() + rate;
38 }
39 npv_prime
40}
41
42pub fn pv_prime2_r<T: FloatLike>(rate: T, n: T, cash_flow: T) -> T {
55 cash_flow * n * (n + T::one()) / (rate + T::one()).powf(n + T::two())
56}
57
58pub fn npv_prime2_r<T: FloatLike>(rate: T, cash_flows: &[T]) -> T {
70 let mut powf_acc = (T::one() + rate) * (T::one() + rate);
73 let mut npv_prime2 = T::zero();
74 for (t, &cf) in cash_flows.iter().enumerate() {
75 let t = T::from_usize(t);
76 npv_prime2 += cf * t * (t + T::one()) / powf_acc;
77 powf_acc *= T::one() + rate;
78 }
79 npv_prime2
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85 #[cfg(not(feature = "std"))]
86 extern crate std;
87 #[cfg(not(feature = "std"))]
88 use std::{assert, vec};
89
90 #[test]
91 fn test_pv_prime() {
92 let rate = 0.05;
93 let n = 5.0;
94 let cash_flow = 1000.0;
95
96 let result = pv_prime_r(rate, n, cash_flow);
97 let expected: f64 = -3731.07698;
98 assert!(
99 (result - expected).abs() < 1e-5,
100 "Failed on case: {}. Expected: {}, Result: {}",
101 "Rate of 5%, 5th period, cash flow of $1000",
102 expected,
103 result
104 );
105 }
106
107 #[test]
108 fn test_pv_double_prime() {
109 let rate = 0.05;
110 let n = 5.0;
111 let cash_flow = 1000.0;
112
113 let result = pv_prime2_r(rate, n, cash_flow);
114 let expected: f64 = 21320.43990;
115 assert!(
116 (result - expected).abs() < 1e-5,
117 "Failed on case: {}. Expected: {}, Result: {}",
118 "Rate of 5%, 5th period, cash flow of $1000",
119 expected,
120 result
121 );
122 }
123
124 #[test]
125 fn test_npv_prime() {
126 let rate = 0.05;
127 let cash_flows = vec![1000.0, 2000.0, 3000.0];
128 let expected = cash_flows
129 .iter()
130 .enumerate()
131 .map(|(t, &cf)| pv_prime_r(rate, t as f64, cf))
132 .sum::<f64>();
133 let result = npv_prime_r(rate, &cash_flows);
134 assert!(
135 (result - expected).abs() < 1e-5,
136 "Failed on case: {}. Expected: {}, Result: {}",
137 "Rate of 5%, cash flows of $1000, $2000, $3000",
138 expected,
139 result
140 );
141 }
142
143 #[test]
144 fn test_npv_double_prime() {
145 let rate = 0.05;
146 let cash_flows = vec![1000.0, 2000.0, 3000.0];
147 let expected = cash_flows
148 .iter()
149 .enumerate()
150 .map(|(t, &cf)| pv_prime2_r(rate, t as f64, cf))
151 .sum::<f64>();
152
153 let result = npv_prime2_r(rate, &cash_flows);
154 assert!(
155 (result - expected).abs() < 1e-5,
156 "Failed on case: {}. Expected: {}, Result: {}",
157 "Rate of 5%, cash flows of $1000, $2000, $3000",
158 expected,
159 result
160 );
161 }
162}