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}