finance_solution/tvm/
future_value.rs

1//! **Future value calculations.** Given an initial investment amount, a number of periods such as
2//! periods, and fixed or varying interest rates, what is the value of the investment at the end?
3//!
4//! For most common usages, we recommend the [future_value_solution](./fn.future_value_solution.html) function, which provides a better debugging experience and additional features.
5//! 
6//! For more complex scenarios, which involve varying rates in each period, we recommend the [future_value_schedule_solution](./fn.future_value_schedule_solution.html) function.
7//! 
8//! To simply return an f64 value of the future value answer, use the [future_value](./fn.future_value.html) function.
9//! 
10// ! If you need to calculate the present value given a future value, a number of periods, and one
11// ! or more rates use [`present_value`] or related functions.
12// !
13// ! If you need to calculate a fixed rate given a present value, future value, and number of periods
14// ! use [`rate`] or related functions.
15// !
16// ! If you need to calculate the number of periods given a fixed rate and a present and future value
17// ! use [`periods`] or related functions.
18//!
19//! ## Example
20//! 
21//! ```
22//! let (rate, periods, present_value, continuous_compounding) = (0.034, 10, 1_000, false);
23//! let fv = finance_solution::future_value_solution(rate, periods, present_value, continuous_compounding);
24//! dbg!(fv);
25//! ```
26//! Outputs to terminal:
27//! ```text
28//! {
29//!     calculated_field: FutureValue,
30//!     continuous_compounding: false,
31//!     rate: 0.034,
32//!     periods: 10,
33//!     fractional_periods: 10.0,
34//!     present_value: 1000.0,
35//!     future_value: 1397.0288910795477,
36//!     formula: "1397.0289 = 1000.0000 * (1.034000 ^ 10)",
37//!     symbolic_formula: "fv = pv * (1 + r)^n",
38//! }
39//! ```
40//! # Formulas
41//!
42//! ## Simple Compounding
43//!
44//! With simple compound interest, the future value is calculated with:
45//!
46//! > <img src="http://i.upmath.me/svg/future%5C_value%20%3D%20present%5C_value%20%5Ctimes%20(1%2Brate)%5E%7Bperiods%7D" />
47//!
48//! Or with some more commonly-used variable names:
49//!
50//! > <img src="http://i.upmath.me/svg/fv%20%3D%20pv%20%5Ctimes%20(1%2Br)%5En" />
51//!
52//! `n` is often used for the number of periods, though it may be `t` for time if each period is
53//! assumed to be one year as in continuous compounding. `r` is the periodic rate, though this may
54//! appear as `i` for interest.
55//!
56//! Throughout this crate we use `pv` for present value and `fv` for future value. You may see these
57//! values called `P` for principal in some references.
58//!
59//! Within the [TvmSolution](./struct.TvmSolution.html) struct we record the formula used for the particular calculation
60//! using both concrete values and symbols. For example with $1,000 growing at 3.5% per period for
61//! 12 periods using simple compounding the struct contains these fields:
62//! ```text
63//! formula: "1511.0687 = 1000.0000 * (1.035000 ^ 12)",
64//! symbolic_formula: "fv = pv * (1 + r)^n",
65//! ```
66//!
67//! ## Continuous Compounding
68//!
69//! With continuous compounding the formula is:
70//!
71//! > <img src="http://i.upmath.me/svg/future%5C_value%20%3D%20%7Bpresent%5C_value%20%5Ctimes%20e%5E%7Brate%20%5Ctimes%20periods%7D" />
72//!
73//! or:
74//!
75//! > <img src="http://i.upmath.me/svg/fv%20%3D%20pv%20%5Ctimes%20e%5E%7Br%20%5Ctimes%20n%7D" />
76//!
77//! With continuous compounding the period is assumed to be years and `t` (time) is often used as
78//! the variable name. Within this crate we stick with `n` for the number of periods so that it's
79//! easier to compare formulas when they're printed as simple text as part of the [TvmSolution](./struct.TvmSolution.html)
80//! struct. For example with $1,000 growing at 3.5% per period for 12 periods using continuous
81//! compounding the struct contains these fields:
82//! ```text
83//! formula: "1521.9616 = 1000.0000 * 2.718282^(0.035000 * 12)",
84//! symbolic_formula: "fv = pv * e^(rt)",
85//! ```
86//! This is the same as the example in the previous section except that it uses continuous
87//! compounding.
88
89use log::warn;
90
91use super::tvm::*;
92
93#[allow(unused_imports)]
94use crate::{rate::*, periods::*, present_value::*};
95
96/// Returns the value of an investment after it has grown or shrunk over time, using a fixed rate.
97///
98/// See the [future_value](./index.html) module page for the formulas.
99///
100/// Related functions:
101/// * To calculate a future value with a fixed rate and return a struct that shows the formula and
102/// optionally produces the the period-by-period values use [`future_value_solution`].
103/// * To calculate the future value if the rates vary by period use [`future_value_schedule`] or
104/// [`future_value_schedule_solution`].
105///
106/// # Arguments
107/// * `rate` - The rate at which the investment grows or shrinks per period, expressed as a
108/// floating point number. For instance 0.05 would mean 5% growth. Often appears as `r` or `i` in
109/// formulas.
110/// * `periods` - The number of periods such as quarters or periods. Often appears as `n` or `t`.
111/// * `present_value` - The starting value of the investment. May appear as `pv` in formulas, or `C`
112/// for cash flow or `P` for principal.
113/// * `continuous_compounding` - True for continuous compounding, false for simple compounding.
114///
115/// # Panics
116/// The call will fail if `rate` is less than -1.0 as this would mean the investment is
117/// losing more than its full value every period.
118///
119/// # Examples
120/// Investment that grows quarter by quarter.
121/// ```
122/// use finance_solution::*;
123///
124/// // The investment grows by 3.4% per quarter.
125/// let rate = 0.034;
126///
127/// // The investment will grow for 5 quarters.
128/// let periods = 5;
129///
130/// // The initial investment is $250,000.
131/// let present_value = -250_000;
132///
133/// let continuous_compounding = false;
134///
135/// let future_value = future_value(rate, periods, present_value, continuous_compounding);
136/// // Confirm that the future value is correct to four decimal places (one
137/// // hundredth of a cent).
138/// assert_rounded_4(295_489.9418, future_value);
139/// ```
140/// Investment that loses money each year.
141/// ```
142/// # use finance_solution::*;
143/// // The investment loses 5% per year.
144/// let rate = -0.05;
145///
146/// // The investment will shrink for 6 periods.
147/// let periods = 6;
148///
149/// // The initial investment is $10,000.75.
150/// let present_value = -10_000.75;
151///
152/// let continuous_compounding = false;
153///
154/// let future_value = future_value(rate, periods, present_value, continuous_compounding);
155/// // Confirm that the future value is correct to the penny.
156/// assert_rounded_2(7351.47, future_value);
157/// ```
158/// Error case: The investment loses 105% per year. There's no way to work out
159/// what this means so the call will panic.
160/// ```should_panic
161/// # use finance_solution::future_value;
162/// let (rate, periods, present_value, continuous_compounding) = (-1.05, 6, 10_000.75, false);
163/// let future_value = future_value(rate, periods, present_value, continuous_compounding);
164/// ```
165pub fn future_value<T>(rate: f64, periods: u32, present_value: T, continuous_compounding: bool) -> f64
166    where T: Into<f64> + Copy
167{
168    future_value_internal(rate, periods as f64, present_value.into(), continuous_compounding)
169}
170
171/// Calculates the value of an investment after it has grown or shrunk over time and returns a
172/// struct with the inputs and the calculated value. This is used for keeping track of a collection
173/// of financial scenarios so that they can be examined later.
174///
175/// See the [future_value](./index.html) module page for the formulas.
176///
177/// Related functions:
178/// * For simply calculating a single future value using a fixed rate use [`future_value`].
179/// * To calculate the future value if the rates vary by period use [`future_value_schedule`].
180/// * To calculate the future value with varying rates and return a struct that can produce the
181/// period-by-period values use [`future_value_schedule_solution`].
182///
183/// # Arguments
184/// * `rate` - The rate at which the investment grows or shrinks per period, expressed as a
185/// floating point number. For instance 0.05 would mean 5% growth. Often appears as `r` or `i` in
186/// formulas.
187/// * `periods` - The number of periods such as quarters or periods. Often appears as `n` or `t`.
188/// * `present_value` - The starting value of the investment. May appear as `pv` in formulas, or `C`
189/// for cash flow or `P` for principal.
190/// * `continuous_compounding` - True for continuous compounding, false for simple compounding.
191///
192/// # Panics
193/// The call will fail if `rate` is less than -1.0 as this would mean the investment is
194/// losing more than its full value every period.
195///
196/// # Examples
197/// Calculate a future value and examine the period-by-period values.
198/// ```
199/// use finance_solution::*;
200/// // The rate is 1.2% per month.
201/// let rate = 0.012;
202///
203/// // The investment will grow for 8 months.
204/// let periods = 8;
205///
206/// // The initial investment is $200,000.
207/// let present_value = -200_000;
208///
209/// let continuous_compounding = false;
210///
211/// let solution = future_value_solution(rate, periods, present_value, continuous_compounding);
212/// dbg!(&solution);
213///
214/// let future_value = solution.future_value();
215/// assert_rounded_4(future_value, 220_026.0467);
216///
217/// // Examine the formulas.
218/// let formula = solution.formula();
219/// dbg!(&formula);
220/// assert_eq!(formula, "220026.0467 = 200000.0000 * (1.012000 ^ 8)");
221/// let symbolic_formula = solution.symbolic_formula();
222/// dbg!(&symbolic_formula);
223/// assert_eq!(symbolic_formula, "fv = -pv * (1 + r)^n");
224///
225/// // Calculate the value at the end of each period.
226/// let series = solution.series();
227/// dbg!(&series);
228/// ```
229/// Create a collection of future value calculations ranging over several interest rates.
230/// ```
231/// # use finance_solution::*;
232///
233/// // The initial investment is $100,000.
234/// let present_value = -100_000;
235///
236/// // The investment will grow for 12 periods.
237/// let periods = 12;
238///
239/// let continuous_compounding = false;
240///
241/// // We'll keep a collection of the calculated future values along with their inputs.
242/// let mut scenarios = vec![];
243///
244/// for i in 2..=15 {
245///     // The rate is between 2% and 15% per year.
246///     let rate = f64::from(i) / 100.0;
247///     // Calculate the future value for this periodic rate and add the details to the collection.
248///     scenarios.push(future_value_solution(rate, periods, present_value, continuous_compounding));
249/// }
250/// dbg!(&scenarios);
251/// assert_eq!(14, scenarios.len());
252///
253/// // Keep only the scenarios where the future value was between $200,000 and $400,000.
254/// scenarios.retain(|x| x.future_value() >= 200_000.00 && x.future_value() <= 400_000.00);
255/// dbg!(&scenarios);
256/// assert_eq!(7, scenarios.len());
257///
258/// // Check the formulas for the first of the remainingc scenarios.
259/// let formula = scenarios[0].formula();
260/// dbg!(&formula);
261/// assert_eq!("201219.6472 = 100000.0000 * (1.060000 ^ 12)", formula);
262/// let symbolic_formula = scenarios[0].symbolic_formula();
263/// dbg!(&symbolic_formula);
264/// assert_eq!("fv = -pv * (1 + r)^n", symbolic_formula);
265/// ```
266pub fn future_value_solution<T>(rate: f64, periods: u32, present_value: T, continuous_compounding: bool) -> TvmSolution
267    where T: Into<f64> + Copy
268{
269    future_value_solution_internal(rate, periods as f64, present_value.into(), continuous_compounding)
270}
271
272/// Calculates a future value based on rates that change for each period.
273///
274/// Related functions:
275/// * To calculate the future value with varying rates and return a struct that can produce the
276/// period-by-period values use [`future_value_schedule_solution`].
277/// * If there is a single fixed rate use [`future_value`] or [`future_value_solution`].
278///
279/// # Arguments
280/// * `rates` - A collection of rates, one for each period.
281/// * `present_value` - The starting value of the investment.
282///
283/// # Panics
284/// The call will fail if any of the rates is less than -1.0 as this would mean the investment is
285/// losing more than its full value.
286///
287/// # Examples
288/// Calculate the value of an investment whose rates vary by year.
289/// ```
290/// use finance_solution::*;
291/// // The rates vary by year: 4% followed by -3.9%, 10.6%, and -5.7%.
292/// let rates = [0.04, -0.039, 0.106, -0.057];
293///
294/// // The initial investment is $75,000.
295/// let present_value = -75_000.00;
296///
297/// let future_value = future_value_schedule(&rates, present_value);
298/// dbg!(&future_value);
299/// assert_rounded_4(78_178.0458, future_value);
300/// ```
301/// Error case: One of the rates shows a drop of over 100%. There's no way to work out what this
302/// means so the call will panic.
303/// ```should_panic
304/// # use finance_solution::future_value_schedule;
305/// let rates = [0.116, -100.134, -0.09, 0.086];
306/// let present_value = -4_000.00;
307/// let schedule = future_value_schedule(&rates, present_value);
308/// ```
309pub fn future_value_schedule<T>(rates: &[f64], present_value: T) -> f64
310    where T: Into<f64> + Copy
311{
312    let present_value= present_value.into();
313    let periods = rates.len();
314
315    // Check the parameters including all of the provided rates.
316    for rate in rates {
317        check_future_value_parameters(*rate, periods as f64, present_value);
318    }
319
320    let mut future_value = -present_value;
321    for i in 0..periods {
322        future_value *= 1.0 + rates[i];
323    }
324
325    future_value
326}
327
328/// Calculates a future value based on rates that change for each period, returning a struct with
329/// all of the inputs and results.
330///
331/// Related functions:
332/// * For simply calculating a single future value using a fixed rate use [`future_value`].
333/// * To calculate a future value with a fixed rate and return a struct that shows the formula and
334/// optionally produces the the period-by-period values use [`future_value_solution`].
335/// * To calculate the future value if the rates vary by period use [`future_value_schedule`].
336///
337/// # Arguments
338/// * `rates` - A collection of rates, one for each period.
339/// * `present_value` - The starting value of the investment.
340///
341/// # Panics
342/// The call will fail if any of the rates is less than -1.0 as this would mean the investment is
343/// losing more than its full value.
344///
345/// # Examples
346/// Calculate the value of an investment whose rates vary by year.
347/// ```
348/// use finance_solution::*;
349/// // The rates vary by year: 8.1% followed by 11%, 4%, and -2.3%.
350/// let rates = [0.081, 0.11, 0.04, -0.023];
351///
352/// // The initial investment is $10,000.
353/// let present_value = -10_000.00;
354///
355/// let solution = future_value_schedule_solution(&rates, present_value);
356/// dbg!(&solution);
357///
358/// let future_value = solution.future_value();
359/// dbg!(&future_value);
360/// assert_rounded_4(future_value, 12_192.0455);
361///
362/// // Calculate the value for each period.
363/// let series = solution.series();
364/// dbg!(&series);
365/// ```
366/// Error case: One of the rates shows a drop of over 100%. There's no way to work out what this
367/// means so the call will panic.
368/// ```should_panic
369/// # use finance_solution::*;
370/// let rates = [0.116, -100.134, -0.09, 0.086];
371/// let present_value = -4_000.00;
372/// let schedule = future_value_schedule(&rates, present_value);
373/// ```
374pub fn future_value_schedule_solution<T>(rates: &[f64], present_value: T) -> TvmScheduleSolution
375    where T: Into<f64> + Copy
376{
377    let future_value = future_value_schedule(rates, present_value);
378    TvmScheduleSolution::new(TvmVariable::FutureValue, rates, present_value.into(), future_value)
379}
380
381pub(crate) fn future_value_internal(rate: f64, periods: f64, present_value: f64, continuous_compounding: bool) -> f64 {
382    check_future_value_parameters(rate, periods, present_value);
383    let future_value = if continuous_compounding {
384        // http://www.edmichaelreggie.com/TMVContent/rate.htm
385        -present_value * std::f64::consts::E.powf(rate * periods)
386    } else {
387        -present_value * (1.0 + rate).powf(periods)
388    };
389    assert!(future_value.is_finite());
390    future_value
391}
392
393pub(crate) fn future_value_solution_internal(rate: f64, periods: f64, present_value: f64, continuous_compounding: bool) -> TvmSolution {
394    let future_value = future_value_internal(rate, periods, present_value, continuous_compounding);
395    let (formula, symbolic_formula) = if continuous_compounding {
396        let formula = format!("{:.4} = {:.4} * {:.6}^({:.6} * {})", future_value, -present_value, std::f64::consts::E, rate, periods);
397        let symbolic_formula = "fv = -pv * e^(rt)";
398        (formula, symbolic_formula)
399    } else {
400        let rate_multiplier = 1.0 + rate;
401        assert!(rate_multiplier >= 0.0);
402        let formula = format!("{:.4} = {:.4} * ({:.6} ^ {})", future_value, -present_value, rate_multiplier, periods);
403        let symbolic_formula = "fv = -pv * (1 + r)^n";
404        (formula, symbolic_formula)
405    };
406    TvmSolution::new_fractional_periods(TvmVariable::FutureValue, continuous_compounding, rate, periods, present_value, future_value, &formula, symbolic_formula)
407}
408
409fn check_future_value_parameters(rate: f64, _periods: f64, present_value: f64) {
410    assert!(rate.is_finite(), "The rate must be finite (not NaN or infinity)");
411    assert!(rate >= -1.0, "The rate must be greater than or equal to -1.0 because a rate lower than -100% would mean the investment loses more than its full value in a period.");
412    if rate.abs() > 1. {
413        warn!("You provided a periodic rate ({}) greater than 1. Are you sure you expect a {}% return?", rate, rate * 100.0);
414    }
415    assert!(present_value.is_finite(), "The present value must be finite (not NaN or infinity)");
416}
417
418#[cfg(test)]
419mod tests {
420    use super::*;
421    use crate::initialized_vector;
422
423    #[should_panic]
424    #[test]
425    fn test_future_value_error_rate_low() {
426        future_value(-101.0, 5, 250_000.00, false);
427    }
428
429    #[should_panic]
430    #[test]
431    fn test_future_value_solution_6() {
432        // test infinity on rate
433        let rate_of_return = 1.0f64 / 0.0f64;
434        let periods = 6;
435        let present_value = 5_000.00;
436        let _should_panic = future_value_solution(rate_of_return, periods, present_value, false);
437    }
438
439    #[should_panic]
440    #[test]
441    fn test_future_value_solution_7() {
442        // test infinity on fv
443        let rate_of_return = 0.03;
444        let periods = 6;
445        let present_value = 1.0f64 / 0.0f64;
446        let _should_panic = future_value_solution(rate_of_return, periods, present_value, false);
447    }
448
449    /*
450    macro_rules! compare_to_excel {
451        ( $r:expr, $n:expr, $pv:expr, $fv_excel:expr, $fv_manual_simple:expr, $fv_manual_cont:expr ) => {
452            println!("$r = {}, $n = {}, $pv = {}, $fv_excel: {}, $fv_manual_simple = {}, $fv_manual_cont = {}", $r, $n, $pv, $fv_excel, $fv_manual_simple, $fv_manual_cont);
453            assert_approx_equal!($fv_excel, $fv_manual_simple);
454
455            let fv_calc_simple = future_value($r, $n, $pv, false);
456            println!("fv_calc_simple = {}", fv_calc_simple);
457            assert_approx_equal!($fv_excel, fv_calc_simple);
458
459            let fv_calc_cont = future_value($r, $n, $pv, true);
460            println!("fv_calc_cont = {}", fv_calc_cont);
461            assert_approx_equal!($fv_manual_cont, fv_calc_cont);
462
463            let ratio = fv_calc_cont / fv_calc_simple;
464            println!("ratio = {}", ratio);
465            assert!(ratio >= 1.0);
466            assert!(ratio < 2.0);
467        }
468    }
469    */
470    
471    fn compare_to_excel (test_case: usize, r: f64, n: u32, pv: f64, fv_excel: f64, fv_manual_simple: f64, fv_manual_cont: f64) {
472        let display = false;
473
474        if display { println!("test_case = {}, r = {}, n = {}, pv = {}, fv_excel: {}, fv_manual_simple = {}, fv_manual_cont = {}", test_case, r, n, pv, fv_excel, fv_manual_simple, fv_manual_cont); }
475        assert_approx_equal!(fv_excel, fv_manual_simple);
476
477        let fv_calc_simple = future_value(r, n, pv, false);
478        if display { println!("fv_calc_simple = {}", fv_calc_simple) };
479        assert_approx_equal!(fv_excel, fv_calc_simple);
480
481        let fv_calc_cont = future_value(r, n, pv, true);
482        if display { println!("fv_calc_cont = {}", fv_calc_cont) };
483        assert_approx_equal!(fv_manual_cont, fv_calc_cont);
484
485        let ratio = fv_calc_cont / fv_calc_simple;
486        if display { println!("ratio = {}", ratio) };
487        assert!(ratio >= 1.0);
488        assert!(ratio < 2.0);
489
490        // Solution with simple compounding.
491        let solution = future_value_solution(r, n, pv, false);
492        if display { dbg!(&solution); }
493        solution.invariant();
494        assert!(solution.calculated_field().is_future_value());
495        assert_eq!(false, solution.continuous_compounding());
496        assert_approx_equal!(r, solution.rate());
497        assert_eq!(n, solution.periods());
498        assert_approx_equal!(n as f64, solution.fractional_periods());
499        assert_approx_equal!(pv, solution.present_value());
500        assert_approx_equal!(fv_excel, solution.future_value());
501
502        // Solution with continuous compounding.
503        let solution = future_value_solution(r, n, pv, true);
504        if display { dbg!(&solution); }
505        solution.invariant();
506        assert!(solution.calculated_field().is_future_value());
507        assert!(solution.continuous_compounding());
508        assert_approx_equal!(r, solution.rate());
509        assert_eq!(n, solution.periods());
510        assert_approx_equal!(n as f64, solution.fractional_periods());
511        assert_approx_equal!(pv, solution.present_value());
512        assert_approx_equal!(fv_manual_cont, solution.future_value());
513
514        let rates = initialized_vector(n as usize, r);
515
516        // Schedule solution.
517        let solution = future_value_schedule_solution(&rates, pv);
518        if display { dbg!(&solution); }
519        solution.invariant();
520        assert!(solution.calculated_field().is_future_value());
521        assert_eq!(n, solution.periods());
522        assert_approx_equal!(pv, solution.present_value());
523        assert_approx_equal!(fv_excel, solution.future_value());
524    }
525
526    #[test]
527    fn test_future_value_against_excel() {
528        compare_to_excel(1, 0.01f64, 90, 1f64, -2.44863267464848f64, -2.44863267464848f64, -2.45960311115695f64);
529        compare_to_excel(2, -0.01f64, 85, -1.5f64, 0.638385185082981f64, 0.638385185082981f64, 0.64112239792309f64);
530        compare_to_excel(3, 0f64, 80, 2.25f64, -2.25f64, -2.25f64, -2.25f64);
531        compare_to_excel(4, 0.05f64, 75, -3.375f64, 131.060314992675f64, 131.060314992675f64, 143.508651750212f64);
532        compare_to_excel(5, -0.05f64, 70, 5.0625f64, -0.139642432836174f64, -0.139642432836174f64, -0.152874253575487f64);
533        compare_to_excel(6, 0.01f64, 65, -7.59375f64, 14.499251769574f64, 14.499251769574f64, 14.5461381703243f64);
534        compare_to_excel(7, -0.01f64, 60, 11.390625f64, -6.23245612973226f64, -6.23245612973226f64, -6.25130754238352f64);
535        compare_to_excel(8, 0f64, 55, -17.0859375f64, 17.0859375f64, 17.0859375f64, 17.0859375f64);
536        compare_to_excel(9, 0.05f64, 50, 25.62890625f64, -293.896914040351f64, -293.896914040351f64, -312.223995610061f64);
537        compare_to_excel(10, -0.05f64, 45, -38.443359375f64, 3.82281753569715f64, 3.82281753569715f64, 4.05190026767808f64);
538        compare_to_excel(11, 0.01f64, 40, 57.6650390625f64, -85.8553853561044f64, -85.8553853561044f64, -86.0261294638861f64);
539        compare_to_excel(12, -0.01f64, 35, -86.49755859375f64, 60.8465082158636f64, 60.8465082158636f64, 60.9537993307622f64);
540        compare_to_excel(13, 0f64, 30, 129.746337890625f64, -129.746337890625f64, -129.746337890625f64, -129.746337890625f64);
541        compare_to_excel(14, 0.05f64, 25, -194.619506835937f64, 659.050728569279f64, 659.050728569279f64, 679.288825069511f64);
542        compare_to_excel(15, -0.05f64, 20, 291.929260253906f64, -104.652530140165f64, -104.652530140165f64, -107.3947731238f64);
543        compare_to_excel(16, 0.01f64, 15, -437.893890380859f64, 508.381212478371f64, 508.381212478371f64, 508.760116525988f64);
544        compare_to_excel(17, -0.01f64, 12, 656.840835571289f64, -582.213779775772f64, -582.213779775772f64, -582.56556073855f64);
545        compare_to_excel(18, 0f64, 10, -985.261253356933f64, 985.261253356933f64, 985.261253356933f64, 985.261253356933f64);
546        compare_to_excel(19, 0.05f64, 7, 1477.8918800354f64, -2079.54228903805f64, -2079.54228903805f64, -2097.22840728772f64);
547        compare_to_excel(20, -0.05f64, 5, -2216.8378200531f64, 1715.34684668614f64, 1715.34684668614f64, 1726.47503019966f64);
548        compare_to_excel(21, 0.01f64, 4, 3325.25673007965f64, -3460.27548760037f64, -3460.27548760037f64, -3460.96303162265f64);
549        compare_to_excel(22, -0.01f64, 3, -4987.88509511947f64, 4839.73991990933f64, 4839.73991990933f64, 4840.47081241187f64);
550        compare_to_excel(23, 0f64, 2, 7481.82764267921f64, -7481.82764267921f64, -7481.82764267921f64, -7481.82764267921f64);
551        compare_to_excel(24, 0.05f64, 1, -11222.7414640188f64, 11783.8785372198f64, 11783.8785372198f64, 11798.1437232237f64);
552        compare_to_excel(25, -0.05f64, 0, 16834.1121960282f64, -16834.1121960282f64, -16834.1121960282f64, -16834.1121960282f64);
553    }
554
555}