finance_solution/convert_rate.rs
1//! **Rate conversions**. Given a rate and number of compound periods per year, what is this rate
2//! when converted to APR, Effective annual, and Periodic rates? Also consider the [`apr`](./fn.apr.html) [`ear`](./fn.ear.html) and [`epr`](./fn.epr.html) helper functions.
3//!
4//! **APR**: **Annual Percentage Rate**, also written as Nominal Rate, or annual discount rate. An annualized represenation of the interest rate.
5//!
6//! ><small>For general use, try the [`apr`](./fn.apr.html) function by providing rate and compounding periods per year, for example `apr(0.034, 12)`.</small>
7//!
8//! ><small>To _calculate_ the Annual Percentage Rate (APR) of a given rate, use the [`convert_ear_to_apr`](./fn.convert_ear_to_apr.html) or [`convert_epr_to_apr`](./fn.convert_epr_to_apr.html) functions.</small>
9//!
10//! ><small>To _convert_ an Annual Percentage Rate (APR) into a different rate, use the [`convert_apr_to_ear`](./fn.convert_apr_to_ear.html) or [`convert_apr_to_epr`](./fn.convert_apr_to_ear.html) functions.</small>
11//!
12//! **EPR**: **Effective Periodic Rate**, also written as **Periodic Rate**. The rate of the compounding period.
13//!
14//! ><small>For general use, try the [`epr`](./fn.epr.html) function by providing rate and compounds_per_year, for example `epr(0.034, 12)`.</small>
15//!
16//! ><small>To <i>calculate</i> the Effective Periodic Rate (EPR) of a given rate use the [`convert_apr_to_epr`](./fn.convert_apr_to_epr.html) or [`convert_ear_to_epr`](./fn.convert_ear_to_epr.html) functions.</small>
17//!
18//! ><small>To _convert_ an Effective Period Rate (EPR) into a different rate, use the [`convert_epr_to_ear`](./fn.convert_epr_to_ear.html) or [`convert_epr_to_apr`](./fn.convert_epr_to_apr.html) functions.</small>
19//!
20//! **EAR**: **Effective Annual Rate**. The effective rate of a year which (typically) has multiple compounding periods within the year.
21//!
22//! ><small>For general use, try the [`ear`](./fn.ear.html) function by providing rate and compounding periods per year, for example `ear(0.034, 12)`.</small>
23//!
24//! ><small>To _calculate_ the Effective Annual Rate (EAR) of a given rate use the [`convert_apr_to_ear`](./fn.convert_apr_to_ear.html) or [`convert_epr_to_ear`](./fn.convert_epr_to_ear.html) functions.</small>
25//!
26//! ><small>To _convert_ an Effective Annual Rate (EAR) into a different rate, use the [`convert_ear_to_apr`](./fn.convert_ear_to_apr.html) or [`convert_ear_to_epr`](./fn.convert_ear_to_epr.html) functions.</small>
27//!
28//! # Examples
29//! All functions in this module can be written with the suffix **_solution**, except for the [`apr`](./fn.apr.html), [`ear`](./fn.ear.html), [`epr`](./fn.epr.html) helper functions which already provide a solution struct.
30//! The solution functions provide helpful information in the `dbg!()` output, for example:
31//!
32//! ```
33//! use finance_solution::*;
34//! // Example 1: Give the apr function an apr and compounding-periods-per-year.
35//! let rate = apr(0.034, 12);
36//! dbg!(rate);
37//! ```
38//! > prints to terminal:
39//! ```text
40//! {
41//! input_name: Apr
42//! input_rate: 0.034
43//! compounds_per_year: 12
44//! apr_in_percent: 3.4000%
45//! epr_in_percent: 0.2833%
46//! ear_in_percent: 3.4535%
47//! apr: 0.034
48//! epr: 0.0028333333333333335
49//! ear: 0.03453486936028982
50//! apr_formula:
51//! epr_formula: 0.034 / 12
52//! ear_formula: (1 + (0.034/12))^12 - 1
53//! }
54//! ```
55//! Example 2: explicit call to f64 function
56//! ```
57//! # use finance_solution::*;
58//! let apr = convert_apr_to_ear(0.034, 12);
59//! dbg!(apr);
60//! ```
61//! > prints to terminal:
62//! ```text
63//! 0.03453486936028982
64//! ```
65//! Example 3: explicit call to a `_solution` function
66//! ```
67//! # use finance_solution::*;
68//! let apr = convert_rate::convert_apr_to_ear_solution(0.034, 12); // provides same output as apr! macro
69//! dbg!(apr.ear());
70//! ```
71//! > prints to terminal:
72//! ```text
73//! {
74//! input_name: Apr
75//! input_rate: 0.034
76//! compounds_per_year: 12
77//! apr_in_percent: 3.4000%
78//! epr_in_percent: 0.2833%
79//! ear_in_percent: 3.4535%
80//! apr: 0.034
81//! epr: 0.0028333333333333335
82//! ear: 0.03453486936028982
83//! apr_formula:
84//! epr_formula: 0.034 / 12
85//! ear_formula: (1 + (0.034/12))^12 - 1
86//! }
87//! ```
88//! Here are a few variations of how someone can use the `convert_rate` module functions:
89//! ```
90//! # use finance_solution::*;
91//! // What is the future value of $500 in 1 year
92//! // if the APR is 3.4% and it's compounded monthly?
93//! // Solve twice, first using EPR and then using EAR.
94//!
95//! // to solve, first convert the annual rate into a periodic rate (monthly):
96//! let epr = convert_rate::convert_apr_to_epr(0.034, 12);
97//! assert_approx_equal!(epr, 0.002833333333333333);
98//!
99//! // then solve for future value:
100//! let fv = future_value::future_value_solution;
101//! let answer_1 = fv(epr, 12, 500, false);
102//! dbg!(&answer_1);
103//! ```
104//! > prints to terminal:
105//! ```text
106//! {
107//! calculated_field: FutureValue
108//! rate: 0.0028333333333333335
109//! periods: 12
110//! present_value: 500.0
111//! future_value: 517.2674346801452
112//! formula: "500.0000 * (1.002833 ^ 12)"
113//! }
114//! ```
115//! Now let's doublecheck the previous answer.
116//! ```
117//! # use finance_solution::*;
118//! // Double-check the previous answer_1 by solving the future_value
119//! // using 1 year as the period and the effective annual rate,
120//! // instead of using 12 monthly periods of the periodic rate.
121//! let rate = apr(0.034, 12);
122//! let answer_2 = future_value::future_value_solution(rate.ear(), 1, 500, false);
123//! dbg!(&answer_2.future_value()); // outputs: 517.2674346801449
124//! // assert_approx_equal!(answer_1.future_value, answer_2.future_value); // true
125//! ```
126//!
127//! Note: you might notice the last two decimal places are different:<br>
128//! > &answer1.future_value() = 517.26743468014**52**<br>
129//! > &answer2.future_value() = 517.26743468014**49**<br>
130//!
131//! This is not a mistake, this is a natural phenomenon of computer calculations to have slight inaccuracies in floating point number calculations. Both answers are technically correct.
132//! Users of the crate can use our [`round`](../round/index.html) module, or [`assert_approx_equal!`](../macro.assert_approx_equal.html) macro for working with floating point representations.
133//! Notice how we used [`assert_approx_equal!`](./macro.assert_approx_equal.html) in the example above to assert two slightly different numbers as being equal.
134//!
135//! Now you've learned Time-Value-of-Money problems can be
136//! solved using different rates and periods, while providing the same
137//! correct answer. And you've learned how to use this crate for rate conversions! 😊
138
139use log::{warn};
140
141// Import needed for the function references in the Rustdoc comments.
142#[allow(unused_imports)]
143use crate::tvm_convert_rate::*;
144use crate::*;
145
146fn assert_inputs(rate:f64, periods:u32, fn_type: ConvertRateVariable) {
147 assert!(periods >= 1);
148 assert!(rate.is_finite());
149 if fn_type.is_ear() {
150 assert!(rate > -1.0, "The Effective Annual Rate (EAR) must be greater than -100% or the exponential formula will create an imaginary number.");
151 }
152 if rate > 1. || rate < -1. {
153 warn!("You provided an rate of {}%. Are you sure?", rate*100.);
154 }
155 if periods > 366 {
156 warn!("You provided more than 366 compounding periods in a year (You provided {}). Are you sure?", periods);
157 }
158}
159
160
161/// Helper function to convert an quoted annual rate (apr) into all possible conversions (ear, epr). Returns a solution struct.
162pub fn apr(apr:f64, compounding_periods_in_year:u32) -> ConvertRateSolution {
163 assert_inputs(apr, compounding_periods_in_year, tvm_convert_rate::ConvertRateVariable::Apr);
164 let ear = (1_f64 + (apr/compounding_periods_in_year as f64)).powf(compounding_periods_in_year as f64) - 1_f64;
165 let epr = convert_rate::convert_apr_to_epr(apr, compounding_periods_in_year);
166 let apr_in_percent = format!("{:.4}%", apr * 100.);
167 let epr_in_percent = format!("{:.4}%", epr * 100.);
168 let ear_in_percent = format!("{:.4}%", ear * 100.);
169 let apr_formula = format!("");
170 let epr_formula = format!("{} / {}", apr, compounding_periods_in_year);
171 let ear_formula = format!("(1 + ({}/{}))^{} - 1", apr, compounding_periods_in_year, compounding_periods_in_year);
172 tvm_convert_rate::ConvertRateSolution::new(tvm_convert_rate::ConvertRateVariable::Apr, apr, compounding_periods_in_year, apr_in_percent, epr_in_percent, ear_in_percent, apr, epr, ear, &apr_formula, &epr_formula, &ear_formula,)
173}
174
175/// Helper function to convert an APR into an EAR using continuous compounding. Returns solution struct.
176pub fn apr_continuous(apr:f64) -> ConvertRateSolution {
177 let compounding_periods_in_year = 1; // not used
178 assert_inputs(apr, compounding_periods_in_year, tvm_convert_rate::ConvertRateVariable::AprContinuous);
179 // formula: e^apr - 1
180 let e: f64 = 2.71828182845904;
181 let ear: f64;
182 if apr < 0.0 {
183 // when apr is negative...
184 ear = (e.powf(apr.abs()) - 1_f64) * -1_f64;
185 } else {
186 ear = e.powf(apr) - 1_f64;
187 }
188 let epr = 0.0; // epr cannot exist for infinite periods
189 let apr_in_percent = format!("{:.4}%", apr * 100.);
190 let epr_in_percent = format!("NaN"); // epr cannot exist for infinite periods
191 let ear_in_percent = format!("{:.4}%", ear * 100.);
192 let apr_formula = format!("");
193 let epr_formula = format!("");
194 let ear_formula = format!("({}^{} - 1", e, apr);
195 tvm_convert_rate::ConvertRateSolution::new(tvm_convert_rate::ConvertRateVariable::AprContinuous, apr, compounding_periods_in_year, apr_in_percent, epr_in_percent, ear_in_percent, apr, epr, ear, &apr_formula, &epr_formula, &ear_formula,)
196}
197
198/// Helper function to convert an EAR into an APR using continuous compounding. Returns solution struct.
199pub fn ear_continuous(ear:f64) -> ConvertRateSolution {
200 let compounding_periods_in_year = 1; // not used
201 assert_inputs(ear, compounding_periods_in_year, tvm_convert_rate::ConvertRateVariable::EarContinuous);
202 // formula: e^apr - 1
203 let apr: f64;
204 if ear < 0.0 {
205 // when ear is negative...
206 apr = (ear.abs() + 1_f64).ln() * -1_f64;
207 } else {
208 // APR = ln (EAR + 1)
209 apr = (ear + 1_f64).ln();
210 }
211 let epr = 0.0; // epr cannot exist for infinite periods
212 let apr_in_percent = format!("{:.4}%", apr * 100.);
213 let epr_in_percent = format!("NaN"); // epr cannot exist for infinite periods
214 let ear_in_percent = format!("{:.4}%", ear * 100.);
215 let apr_formula = format!("(ln({} + 1)", apr);
216 let epr_formula = format!("");
217 let ear_formula = format!("");
218 tvm_convert_rate::ConvertRateSolution::new(tvm_convert_rate::ConvertRateVariable::EarContinuous, ear, compounding_periods_in_year, apr_in_percent, epr_in_percent, ear_in_percent, apr, epr, ear, &apr_formula, &epr_formula, &ear_formula,)
219}
220/// Helper function to convert an effective annual rate (ear) into all possible conversions (apr, epr). Returns a solution struct.
221pub fn ear(ear:f64, compounding_periods_in_year:u32) -> ConvertRateSolution {
222 convert_rate::assert_inputs(ear, compounding_periods_in_year, tvm_convert_rate::ConvertRateVariable::Ear);
223 let apr = convert_rate::convert_ear_to_apr(ear, compounding_periods_in_year);
224 let epr = convert_rate::convert_ear_to_epr(ear, compounding_periods_in_year);
225 let apr_in_percent = format!("{:.4}%", apr * 100.);
226 let epr_in_percent = format!("{:.4}%", epr * 100.);
227 let ear_in_percent = format!("{:.4}%", ear * 100.);
228 let apr_formula = format!("{} * {}", epr, compounding_periods_in_year);
229 let epr_formula = format!("(1 + {})^(1 / {}) - 1", ear, compounding_periods_in_year);
230 let ear_formula = format!("{}", ear);
231 tvm_convert_rate::ConvertRateSolution::new(tvm_convert_rate::ConvertRateVariable::Ear, ear, compounding_periods_in_year, apr_in_percent, epr_in_percent, ear_in_percent, apr, epr, ear, &apr_formula, &epr_formula, &ear_formula,)
232}
233
234/// Helper function to convert a periodic interest rate (EPR) to all rate conversions. Returns solution struct.
235///
236/// Note: an EPR of 0.99 with a large number of periods can create decimal inaccuracies due to floating point representation.
237/// The epr conversion method is tested and guaranteed accurate up to 780 periods between rates -0.034 and 0.989 however any rates outside this
238/// range may result in floating point representation / rounding errors (extremely small differences like 0.00001, but if the period count is an extreme case like 2000, this can result in a difference of $1-$4 on a TVM problem).
239///
240pub fn epr(epr:f64, compounding_periods_in_year:u32) -> ConvertRateSolution {
241 convert_rate::assert_inputs(epr, compounding_periods_in_year, tvm_convert_rate::ConvertRateVariable::Epr);
242 let apr = epr * compounding_periods_in_year as f64;
243 let ear = convert_rate::convert_apr_to_ear(apr, compounding_periods_in_year);
244 let apr_in_percent = format!("{:.4}%", apr * 100.);
245 let epr_in_percent = format!("{:.4}%", epr * 100.);
246 let ear_in_percent = format!("{:.4}%", ear * 100.);
247 let apr_formula = format!("{} * {}", epr, compounding_periods_in_year);
248 let epr_formula = format!("");
249 let ear_formula = format!("(1 + {})^{} - 1", epr, compounding_periods_in_year);
250 tvm_convert_rate::ConvertRateSolution::new(tvm_convert_rate::ConvertRateVariable::Epr, epr, compounding_periods_in_year, apr_in_percent, epr_in_percent, ear_in_percent, apr, epr, ear, &apr_formula, &epr_formula, &ear_formula,)
251}
252
253
254/// Convert a nominal interest rate (Annual rate, APR) to EAR (effective annual rate). Returns f64.
255///
256/// Related Functions:
257/// * [`apr`](./fn.apr.html) to convert APR to all forms of rate conversion, and return a custom type with additional functionality and extra information available in the `dbg!()`.
258/// * [`convert_apr_to_ear_solution`](./fn.convert_apr_to_ear_solution.html) to convert APR to EAR and return a custom type with additional functionality and extra information available in the `dbg!()`.
259///
260/// The formula:
261///
262// EAR = (1 + (apr/periods))<sup>periods</sup> - 1
263// Latex formula: EAR=\left(1+\left(\frac{APR}{periods}\right)\right)^{periods}-1
264/// > <img src="http://i.upmath.me/svg/EAR%3D%5Cleft(1%2B%5Cfrac%7BAPR%7D%7Bperiods%7D%5Cright)%5E%7Bperiods%7D-1" />
265///
266/// # Arguments
267/// * `rate` - The input rate, expressed as a floating point number.
268/// For instance 0.05 indicates 5%. Often appears as `r` or `i` in formulas.
269/// * `periods` - The number of compounding periods in a year. Often appears as `n` or `t`. Must be u32.
270///
271/// # Panics
272/// * `periods` - must be a u32 value greater than 0.
273///
274/// # Examples
275/// Convert annual rate to effective annual rate.
276/// ```
277/// use finance_solution::*;
278/// // The annual percentage rate is 3.4% and 12 compounding periods per year.
279/// let nominal_rate = 0.034;
280/// let periods = 12;
281///
282/// let effective_annual_rate = convert_rate::convert_apr_to_ear(nominal_rate, periods);
283///
284/// // Confirm that the EAR is correct.
285/// assert_approx_equal!(0.034535, effective_annual_rate);
286/// ```
287pub fn convert_apr_to_ear(apr: f64, compounding_periods_in_year: u32) -> f64 {
288 assert_inputs(apr, compounding_periods_in_year, ConvertRateVariable::Apr);
289 (1_f64 + (apr/compounding_periods_in_year as f64)).powf(compounding_periods_in_year as f64) - 1_f64
290}
291
292/// Convert an APR to EAR (effective annual rate). Returns a custom type with additional functionality and extra information available in the dbg!().
293///
294/// Related Functions:
295/// * [`apr`](./fn.apr.html) macro to convert APR to all forms of rate conversion, and return a custom type with additional functionality and extra information available in the dbg!().
296/// * [`convert_apr_to_ear`](./fn.convert_apr_to_ear.html) to convert APR to EAR and return the f64 value instead of a solution struct.
297///
298/// The formula:
299///
300// EAR = (1 + (apr/periods))<sup>periods</sup> - 1
301// Latex formula: EAR=\left(1+\left(\frac{APR}{periods}\right)\right)^{periods}-1
302/// > <img src="http://i.upmath.me/svg/EAR%3D%5Cleft(1%2B%5Cfrac%7BAPR%7D%7Bperiods%7D%5Cright)%5E%7Bperiods%7D-1" />
303///
304/// # Arguments
305/// * `rate` - The input rate, expressed as a floating point number.
306/// For instance 0.05 indicates 5%. Often appears as `r` or `i` in formulas.
307/// * `compounding_periods_in_year` - The number of compounding periods in a year. Often appears as `n` or `t`. Must be u32.
308///
309/// # Panics
310/// * `periods` - must be a u32 value greater than 0.
311///
312/// # Example
313/// /// Convert annual rate to effective annual rate.
314/// ```
315/// use finance_solution::*;
316/// // The annual percentage rate is 3.4%.
317/// let nominal_rate = 0.034;
318///
319/// // There are 12 compounding periods per year (monthly compounding).
320/// let periods = 12;
321///
322/// let effective_annual_rate = convert_apr_to_ear_solution(nominal_rate, periods).ear();
323///
324/// // Confirm that the EAR is correct.
325/// assert_approx_equal!(0.034535, effective_annual_rate);
326/// ```
327
328pub fn convert_apr_to_ear_solution(apr: f64, compounding_periods_in_year: u32) -> ConvertRateSolution {
329 assert_inputs(apr, compounding_periods_in_year, ConvertRateVariable::Apr);
330 self::apr(apr, compounding_periods_in_year)
331}
332
333/// Convert APR (annual rate) to periodic rate. Returns f64.
334///
335/// Related Functions:
336/// * [`apr`](./fn.apr.html) macro to convert APR to all forms of rate conversion, and return a custom type with additional functionality and extra information available in the dbg!().
337/// * [`convert_apr_to_epr_solution`](./fn.convert_apr_to_epr_solution.html) to convert APR to EPR and return a custom type with additional functionality and extra information available in the dbg!().
338///
339/// The formula:
340///
341// Periodic Rate = apr / compounding_periods_in_year
342// Latex formula: EPR=\frac{APR}{compounding\_periods\_in\_year}
343/// > <img src="http://i.upmath.me/svg/EPR%3D%5Cfrac%7BAPR%7D%7Bcompounding%5C_periods%5C_in%5C_year%7D" />
344///
345/// # Arguments
346/// * `rate` - The input rate, expressed as a floating point number.
347/// For instance 0.05 would mean 5%. Often appears as `r` or `i` in formulas.
348/// * `compounding_periods_in_year` - The number of compounding periods in a year. Often appears as `n` or `t`.
349///
350/// # Panics
351/// * `compounding_periods_in_year` - must be a u32 value greater than 0.
352///
353/// # Example
354/// Convert annual rate to periodic rate.
355/// ```
356/// use finance_solution::*;
357/// // The annual percentage rate is 3.4%.
358/// // There are 12 compounding periods per year.
359/// let nominal_rate = 0.034;
360/// let periods = 12;
361///
362/// let periodic_rate = convert_apr_to_epr(nominal_rate, periods);
363///
364/// // Confirm that the periodic value is correct to six decimal places.
365/// assert_approx_equal!(0.00283333, periodic_rate);
366/// ```
367pub fn convert_apr_to_epr(apr: f64, compounding_periods_in_year: u32) -> f64 {
368 assert_inputs(apr, compounding_periods_in_year, ConvertRateVariable::Apr);
369 apr / compounding_periods_in_year as f64
370}
371/// Convert APR (annual rate) to periodic rate. Returns a custom solution type.
372///
373/// Related Functions:
374/// * [`apr`](./fn.apr.html) macro to convert APR to all forms of rate conversion, and return a custom type with additional functionality and extra information available in the dbg!().
375/// * [`convert_apr_to_epr`](./fn.convert_apr_to_epr.html) to convert APR to EPR and return a single f64 value instead of a solution struct.
376///
377/// The formula:
378///
379// Periodic Rate = apr / compounding_periods_in_year
380// Latex formula: EPR=\frac{APR}{compounding\_periods\_in\_year}
381/// > <img src="http://i.upmath.me/svg/EPR%3D%5Cfrac%7BAPR%7D%7Bcompounding%5C_periods%5C_in%5C_year%7D" />
382///
383/// # Arguments
384/// * `rate` - The input rate, expressed as a floating point number.
385/// For instance 0.05 would mean 5%. Often appears as `r` or `i` in formulas.
386/// * `compounding_periods_in_year` - The number of compounding periods in a year. Often appears as `n` or `t`.
387///
388/// # Panics
389/// * `compounding_periods_in_year` - must be a u32 value greater than 0.
390///
391/// # Example
392/// Convert annual rate to periodic rate.
393/// ```
394/// use finance_solution::*;
395/// // The annual percentage rate is 3.4%.
396/// // There are 12 compounding periods per year.
397/// let nominal_rate = 0.034;
398/// let periods = 12;
399///
400/// let apr_to_epr_solution = convert_apr_to_epr_solution(nominal_rate, periods);
401///
402/// // Confirm that the periodic rate is correct to six decimal places.
403/// assert_approx_equal!(0.00283333, apr_to_epr_solution.epr());
404/// ```
405pub fn convert_apr_to_epr_solution(apr: f64, compounding_periods_in_year: u32) -> ConvertRateSolution {
406 assert_inputs(apr, compounding_periods_in_year, ConvertRateVariable::Apr);
407 self::apr(apr, compounding_periods_in_year)
408}
409
410
411/// Convert an EAR to APR. Returns f64.
412///
413/// Related Functions:
414/// * [`ear`](./fn.ear.html) to convert EAR to all forms of rate conversion, and return a custom type with additional functionality and extra information available in the dbg!().
415/// * [`convert_ear_to_apr_solution`](./fn.convert_ear_to_apr_solution.html) to convert EAR to APR and return a custom type with additional functionality and extra information available in the dbg!().
416///
417/// The formula is:
418///
419// Latex formula: APR=( (1+ear)^{(1/compounding\_periods\_in\_year)} - 1)\times compounding\_periods\_in\_year
420/// <img src="http://i.upmath.me/svg/APR%3D(%20(1%2Bear)%5E%7B(1%2Fcompounding%5C_periods%5C_in%5C_year)%7D%20-%201)%5Ctimes%20compounding%5C_periods%5C_in%5C_year" />
421///
422/// <small> Note: This formula involves converting the EAR to EPR first, and then converting the EPR to APR.</small>
423///
424/// # Arguments
425/// * `rate` - The input rate, expressed as a floating point number.
426/// For instance 0.05 would mean 5%. Often appears as `r` or `i` in formulas.
427/// * `periods` - The number of compounding periods in a year. Often appears as `n` or `t`.
428///
429/// # Panics
430/// * `periods` - must be a u32 value greater than 0.
431///
432/// # Example
433/// Convert effective annual rate (EAR) to annual percentage rate (APR).
434/// ```
435/// use finance_solution::*;
436/// // The effective annual rate is 3.4534%
437/// // There are 12 compounding periods per year.
438/// let effective_annual_rate = 0.03453486936;
439/// let periods = 12;
440///
441/// let nominal_rate = convert_rate::convert_ear_to_apr(effective_annual_rate, periods);
442///
443/// // Confirm that the APR is correct.
444/// assert_approx_equal!(0.034, nominal_rate);
445/// ```
446pub fn convert_ear_to_apr(ear: f64, compounding_periods_in_year: u32) -> f64 {
447 assert_inputs(ear, compounding_periods_in_year, ConvertRateVariable::Ear);
448 ((1_f64 + ear).powf(1_f64/compounding_periods_in_year as f64) - 1_f64) * compounding_periods_in_year as f64
449}
450/// Convert an EAR to APR. Returns solution struct with additional information and functionality.
451///
452/// Related Functions:
453/// * [`ear`](./fn.ear.html) general-purpose macro to convert EAR into all rate variations.
454/// * [`convert_ear_to_apr`](./fn.convert_ear_to_apr.html) to convert EAR to APR and return an f64 value.
455///
456/// The formula is:
457///
458// Latex formula: APR=( (1+ear)^{(1/compounding\_periods\_in\_year)} - 1)\times compounding\_periods\_in\_year
459/// <img src="http://i.upmath.me/svg/APR%3D(%20(1%2Bear)%5E%7B(1%2Fcompounding%5C_periods%5C_in%5C_year)%7D%20-%201)%5Ctimes%20compounding%5C_periods%5C_in%5C_year" />
460///
461/// <small> Note: This formula involves converting the EAR to EPR first, and then converting the EPR to APR.</small>
462///
463/// # Arguments
464/// * `rate` - The input rate, expressed as a floating point number.
465/// For instance 0.05 would mean 5%. Often appears as `r` or `i` in formulas.
466/// * `periods` - The number of compounding periods in a year. Often appears as `n` or `t`.
467///
468/// # Panics
469/// * `periods` - must be a u32 value greater than 0.
470///
471/// # Example
472/// Convert effective annual rate (EAR) to annual percentage rate (APR).
473/// ```
474/// use finance_solution::*;
475/// // The effective annual rate is 3.453486936028982%
476/// let effective_annual_rate = 0.03453486936028982;
477///
478/// // There are 12 compounding periods per year.
479/// let periods = 12;
480///
481/// let ear_to_apr_solution = convert_rate::convert_ear_to_apr_solution(effective_annual_rate, periods);
482///
483/// // Confirm that the APR is correct.
484/// assert_approx_equal!(0.034, ear_to_apr_solution.apr());
485/// ```
486pub fn convert_ear_to_apr_solution(ear: f64, compounding_periods_in_year: u32) -> ConvertRateSolution {
487 assert_inputs(ear, compounding_periods_in_year, ConvertRateVariable::Ear);
488 self::ear(ear, compounding_periods_in_year)
489}
490
491
492
493
494
495
496/// Convert an EAR (Effective Annual Rate) to periodic rate (aka EPR, effective periodic rate). Returns f64.
497///
498/// Related Functions:
499/// * [`convert_ear_to_epr_solution`](./fn.convert_ear_to_epr_solution.html) to convert EAR to EPR and return a custom type with extra information available in the dbg!().
500///
501/// The formula is:
502///
503// Periodic Rate = (1 + ear)<sup>(1 / compounding_periods_in_year)</sup> - 1
504// Latex formula: EPR=(1 + ear)^{(1/compounding\_periods\_in\_year)}-1
505/// > <img src="http://i.upmath.me/svg/EPR%3D(1%20%2B%20ear)%5E%7B(1%2Fcompounding%5C_periods%5C_in%5C_year)%7D-1" />
506///
507/// or this formula can be re-written as:
508///
509/// <img src="https://i.upmath.me/svg/EPR%20%3D%20%5Csqrt%5Bperiods%5D%7B1%2Bear%7D%20-%201" />
510///
511/// # Arguments
512/// * `ear` - The input rate (effective annual rate), expressed as a floating point number.
513/// For instance 0.05 would mean 5%. Often appears as `r` or `i` in formulas.
514/// * `periods` - The number of compounding periods in a year. Often appears as `n` or `t`.
515///
516/// # Panics
517/// * `periods` - must be a u32 value greater than or equal to 1.
518///
519/// # Example
520/// Convert effective annual rate to periodic rate.
521/// ```
522/// use finance_solution::*;
523/// // The effective annual rate is 3.4534%.
524/// // There are 12 compounding periods per year.
525/// let effective_annual_rate = 0.03453486936;
526/// let periods = 12;
527///
528/// let periodic_rate = convert_rate::convert_ear_to_epr(effective_annual_rate, periods);
529///
530/// // Confirm that the EPR is correct.
531/// assert_approx_equal!(0.00283333, periodic_rate);
532/// ```
533pub fn convert_ear_to_epr(ear: f64, compounding_periods_in_year: u32) -> f64 {
534 assert_inputs(ear, compounding_periods_in_year, ConvertRateVariable::Ear);
535 (1_f64 + ear).powf(1_f64/compounding_periods_in_year as f64) - 1_f64
536}
537/// Convert an EAR (Effective Annual Rate) to periodic rate (also known as EPR). Returns a solution struct with additional information and functionality.
538/// /// Related Functions:
539/// * [`convert_ear_to_epr`](./fn.convert_ear_to_epr.html) to convert EAR to EPR and return a single f64 value.
540///
541/// The formula is:
542///
543// Periodic Rate = (1 + ear)<sup>(1 / compounding_periods_in_year)</sup> - 1
544// Latex formula: EPR=(1 + ear)^{(1/compounding\_periods\_in\_year)}-1
545/// > <img src="http://i.upmath.me/svg/EPR%3D(1%20%2B%20ear)%5E%7B(1%2Fcompounding%5C_periods%5C_in%5C_year)%7D-1" />
546///
547/// or this formula can be re-written as:
548///
549/// <img src="https://i.upmath.me/svg/EPR%20%3D%20%5Csqrt%5Bperiods%5D%7B1%2Bear%7D%20-%201" />
550///
551/// # Arguments
552/// * `ear` - The input rate (effective annual rate), expressed as a floating point number.
553/// For instance 0.05 would mean 5%. Often appears as `r` or `i` in formulas.
554/// * `periods` - The number of compounding periods in a year. Often appears as `n` or `t`.
555///
556/// # Panics
557/// * `periods` - must be a u32 value greater than or equal to 1.
558///
559/// # Example
560/// Convert effective annual rate to periodic rate.
561/// ```
562/// use finance_solution::*;
563/// // The effective annual rate is 3.4534%.
564/// // There are 12 compounding periods per year.
565/// let effective_annual_rate = 0.03453486936;
566/// let periods = 12;
567///
568/// let ear_to_epr_solution = convert_rate::convert_ear_to_epr_solution(effective_annual_rate, periods);
569///
570/// // Confirm that the EPR is correct.
571/// assert_approx_equal!(0.00283333, ear_to_epr_solution.epr());
572/// ```
573pub fn convert_ear_to_epr_solution(ear: f64, compounding_periods_in_year: u32) -> ConvertRateSolution {
574 assert_inputs(ear, compounding_periods_in_year, ConvertRateVariable::Ear);
575 self::ear(ear, compounding_periods_in_year)
576}
577
578
579/// Convert a periodic rate (aka EPR, effective periodic rate) to EAR (effective annual rate). Return a single f64 value.
580///
581/// Related Functions:
582/// * [`convert_epr_to_ear_solution`](./fn.convert_epr_to_ear_solution.html) to convert EPR to EAR and return a custom type with extra information available in the dbg!().
583///
584/// The formula is:
585///
586// EAR = (1 + epr)<sup>(compounding_periods_in_year)</sup> - 1
587// Latex formula: EAR=(1 + epr)^{compounding\_periods\_in\_year}-1
588/// > <img src="http://i.upmath.me/svg/EAR%3D(1%20%2B%20epr)%5E%7Bcompounding%5C_periods%5C_in%5C_year%7D-1" />
589///
590/// # Arguments
591/// * `epr` - The input rate (periodic rate), expressed as a floating point number.
592/// For instance 0.05 indicates 5%. Often appears as `r` or `i` in formulas.
593/// * `periods` - The number of compounding periods in a year. Often appears as `n` or `t`.
594///
595/// # Panics
596/// * `periods` - must be a u32 value greater than or equal to 1.
597///
598/// # Example
599/// Convert a periodic rate to effective annual rate.
600/// ```
601/// use finance_solution::*;
602/// // The periodic rate is 3.4534%. There are 12 compounding periods per year.
603/// let (periodic_rate, periods) = (0.034, 12);
604///
605/// let ear = convert_rate::convert_epr_to_ear(periodic_rate, periods);
606///
607/// // Confirm that the EAR is correct.
608/// assert_approx_equal!(0.49364182107104493, ear);
609/// ```
610pub fn convert_epr_to_ear(epr: f64, compounding_periods_in_year: u32) -> f64 {
611 assert_inputs(epr, compounding_periods_in_year, ConvertRateVariable::Epr);
612 (1_f64 + epr).powf(compounding_periods_in_year as f64) - 1_f64
613}
614/// Convert a periodic rate (EPR) to effective annual rate (EAR), returning a solution struct with additionality information and features.
615///
616/// Related Functions:
617/// * [`convert_epr_to_ear`](./fn.convert_epr_to_ear.html) to convert EPR to EAR and return a single f64 value.
618///
619/// The formula is:
620///
621// EAR = (1 + epr)<sup>(compounding_periods_in_year)</sup> - 1
622// Latex formula: EAR=(1 + epr)^{compounding\_periods\_in\_year}-1
623/// > <img src="http://i.upmath.me/svg/EAR%3D(1%20%2B%20epr)%5E%7Bcompounding%5C_periods%5C_in%5C_year%7D-1" />
624///
625/// # Arguments
626/// * `epr` - The input rate (periodic rate), expressed as a floating point number.
627/// For instance 0.05 indicates 5%. Often appears as `r` or `i` in formulas.
628/// * `periods` - The number of compounding periods in a year. Often appears as `n` or `t`.
629///
630/// # Panics
631/// * `periods` - must be a u32 value greater than or equal to 1.
632///
633/// # Example
634/// Convert a periodic rate to effective annual rate.
635/// ```
636/// use finance_solution::*;
637/// // The periodic rate is 3.4534%. There are 12 compounding periods per year.
638/// let (periodic_rate, periods) = (0.034, 12);
639///
640/// let epr_to_ear_solution = convert_rate::convert_epr_to_ear_solution(periodic_rate, periods);
641///
642/// // Confirm that the EAR is correct.
643/// assert_approx_equal!(0.49364182107104493, epr_to_ear_solution.ear());
644/// ```
645pub fn convert_epr_to_ear_solution(epr: f64, compounding_periods_in_year: u32) -> ConvertRateSolution {
646 assert_inputs(epr, compounding_periods_in_year, ConvertRateVariable::Epr);
647 self::epr(epr, compounding_periods_in_year)
648}
649
650
651
652/// Convert periodic rate to APR (aka Annual rate, nominal interest rate, Annual Percentage Rate). Returns f64.
653///
654/// Related Functions:
655/// * [`convert_epr_to_apr_solution`](./fn.convert_epr_to_apr_solution.html) to convert EPR to APR and return a solution struct with better debugging and additional information.
656///
657/// The formula is:
658///
659// APR = epr * compounding_periods_per_year
660// Latex formula: APR=periodic\_rate\times compounding\_periods\_per\_year
661/// > <img src="http://i.upmath.me/svg/APR%3Dperiodic%5C_rate%5Ctimes%20compounding%5C_periods%5C_per%5C_year" />
662///
663/// # Arguments
664/// * `epr` - The input rate (periodic rate), expressed as a floating point number.
665/// For instance 0.05 indicates 5%. Often appears as `r` or `i` in formulas.
666/// * `periods` - The number of compounding periods in a year. Often appears as `n` or `t`.
667///
668/// # Panics
669/// * `periods` - must be a u32 value greater than or equal to 1.
670///
671/// # Example
672/// Convert a periodic rate to the annual rate (APR).
673/// ```
674/// use finance_solution::*;
675/// // The periodic rate is 3.4%. There are 12 compounding periods per year.
676/// let (periodic_rate, periods) = (0.034, 12);
677///
678/// let apr = convert_rate::convert_epr_to_apr(periodic_rate, periods);
679///
680/// // Confirm that the APR is correct.
681/// assert_approx_equal!(0.4080, apr);
682/// ```
683pub fn convert_epr_to_apr(epr: f64, compounding_periods_in_year: u32) -> f64 {
684 assert_inputs(epr, compounding_periods_in_year, ConvertRateVariable::Epr);
685 epr * compounding_periods_in_year as f64
686}
687/// Convert periodic rate to APR (aka Annual rate, nominal interest rate, Annual Percentage Rate). Returns a custom solution type.
688///
689/// Related Functions:
690/// * [`convert_epr_to_apr`](./fn.convert_epr_to_apr.html) to convert EPR to APR and return an f64 instead of a full solution struct.
691///
692/// The formula is:
693///
694// APR = epr * compounding_periods_per_year
695// Latex formula: APR=periodic\_rate\times compounding\_periods\_per\_year
696/// > <img src="http://i.upmath.me/svg/APR%3Dperiodic%5C_rate%5Ctimes%20compounding%5C_periods%5C_per%5C_year" />
697///
698/// # Arguments
699/// * `epr` - The input rate (periodic rate), expressed as a floating point number.
700/// For instance 0.05 indicates 5%. Often appears as `r` or `i` in formulas.
701/// * `periods` - The number of compounding periods in a year. Often appears as `n` or `t`.
702///
703/// # Panics
704/// * `periods` - must be a u32 value greater than or equal to 1.
705///
706/// # Example
707/// Convert a periodic rate to the annual rate (APR).
708/// ```
709/// use finance_solution::*;
710/// // The periodic rate is 3.4%. There are 12 compounding periods per year.
711/// let (periodic_rate, periods) = (0.034, 12);
712///
713/// let epr_to_apr_solution = convert_rate::convert_epr_to_apr_solution(periodic_rate, periods);
714///
715/// // Confirm that the APR is correct.
716/// assert_approx_equal!(0.4080, epr_to_apr_solution.apr());
717/// ```
718pub fn convert_epr_to_apr_solution(epr: f64, compounding_periods_in_year: u32) -> ConvertRateSolution {
719 assert_inputs(epr, compounding_periods_in_year, ConvertRateVariable::Epr);
720 self::epr(epr, compounding_periods_in_year)
721}
722
723
724
725#[cfg(test)]
726mod tests {
727 use super::*;
728
729 #[test]
730 fn test_convert_rate_apr_symmetry() {
731 let apr_rates = vec!(0.034, -0.034, 0.00283333333, -0.00283333333, 0.0345348693603, 0.0, -0.0, 1.0, 2.1, 0.00001);
732 let periods = vec![12, 1, 2, 3, 4, 6, 24, 52, 365, 780];
733
734 for rates_i in apr_rates {
735 for &periods_i in periods.iter() {
736 check_rate_conversion_symmetry(rates_i, periods_i);
737
738 fn check_rate_conversion_symmetry(rate:f64, periods:u32) {
739 // apr scenarios
740 let apr_epr = convert_apr_to_epr(rate, periods);
741 let _epr_apr = convert_epr_to_apr(apr_epr, periods);
742 let apr_ = apr(rate, periods);
743 assert_approx_equal!(apr_epr, apr_.epr());
744 assert_approx_equal!(_epr_apr, rate);
745
746 let apr_ear = convert_apr_to_ear(rate, periods);
747 let _ear_apr = convert_ear_to_apr(apr_ear, periods);
748 assert_approx_equal!(apr_ear, apr_.ear());
749 assert_approx_equal!(_ear_apr, rate);
750 }
751
752 }
753 }
754 }
755
756 #[test]
757 fn test_convert_rate_ear_symmetry() {
758 let ear_rates = vec!(0.034, -0.034, 0.00283333333, -0.00283333333, 0.0345348693603, 0.0, -0.0, 1.0, 2.1, 0.00001);
759 let periods = vec![12, 1, 2, 3, 4, 6, 24, 52, 365, 780];
760
761 for rates_i in ear_rates {
762 for &periods_i in periods.iter() {
763 check_rate_conversion_symmetry(rates_i, periods_i);
764
765 fn check_rate_conversion_symmetry(rate:f64, periods:u32) {
766 // ear scenarios
767 let ear_apr = convert_ear_to_apr(rate, periods);
768 let _apr_ear = convert_apr_to_ear(ear_apr, periods);
769 let ear_ = ear(rate, periods);
770 assert_approx_equal!(ear_apr, ear_.apr());
771 assert_approx_equal!(_apr_ear, rate);
772
773 let ear_epr = convert_ear_to_epr(rate, periods);
774 let _epr_ear = convert_epr_to_ear(ear_epr, periods);
775 assert_approx_equal!(ear_epr, ear_.epr());
776 assert_approx_equal!(_epr_ear, rate);
777 }
778
779 }
780 }
781 }
782
783 #[test]
784 fn test_convert_rate_epr_symmetry() {
785 let epr_rates = vec!(0.034, -0.034, 0.00283333333, -0.00283333333, 0.0345348693603, 0.0, -0.039, -0.0, 0.98, 0.00001, 0.98999);
786 let periods = vec![12, 1, 2, 3, 4, 6, 24, 52, 365, 780];
787 // note: epr_rate of 0.99 causes floating point representation error on big periods. Periods over 780 also cause failed tests.
788
789 for rates_i in epr_rates {
790 for &periods_i in periods.iter() {
791 check_rate_conversion_symmetry(rates_i, periods_i);
792
793 fn check_rate_conversion_symmetry(rate:f64, periods:u32) {
794 // epr scenarios
795 let epr_apr = convert_epr_to_apr(rate, periods);
796 let _apr_epr = convert_apr_to_epr(epr_apr, periods);
797 let epr_ = epr(rate, periods);
798 assert_approx_equal!(epr_apr, epr_.apr());
799 assert_approx_equal!(_apr_epr, rate);
800
801 let epr_ear = convert_epr_to_ear(rate, periods);
802 let _ear_epr = convert_ear_to_epr(epr_ear, periods);
803 assert_approx_equal!(epr_ear, epr_.ear());
804 assert_approx_equal!(_ear_epr, rate);
805 }
806
807 }
808 }
809 }
810
811
812
813 #[test]
814 fn test_convert_rates_simple_1() {
815 // test on excel values using 12 periods
816 const PERIODS: u32 = 12;
817 let apr_epr_ear_rates = vec!((0.034, 0.00283333333, 0.0345348693603),
818 (-0.034, -0.002833333333, -0.03347513889),
819 (1.0, 0.08333333333, 1.6130352902247),
820 (-1.0, -0.083333333333, -0.64800437199),
821 (2.1, 0.175, 5.9255520766347),
822 (-2.1, -0.175,-0.90058603794)
823 );
824 for rate_tupe in apr_epr_ear_rates {
825 let ap = convert_apr_to_epr(rate_tupe.0, PERIODS);
826 let ae = convert_apr_to_ear(rate_tupe.0, PERIODS);
827 let pa = convert_epr_to_apr(rate_tupe.1, PERIODS);
828 let pe = convert_epr_to_ear(rate_tupe.1, PERIODS);
829 let ea = convert_ear_to_apr(rate_tupe.2, PERIODS);
830 let ep = convert_ear_to_epr(rate_tupe.2, PERIODS);
831 check_rate_conversion_symmetry(ap, ae, pa, pe, ea, ep);
832
833 fn check_rate_conversion_symmetry(ap:f64, ae:f64, pa:f64, pe:f64, ea:f64, ep:f64) {
834 assert_eq!( round_6(ap), round_6(ep) );
835 assert_eq!( round_6(ae), round_6(pe) );
836 assert_eq!( round_6(pa), round_6(ea) );
837 }
838 }
839 }
840}