finance_solution/tvm/present_value.rs
1//! **Present value calculations.** Given a final amount, a number of periods such as years, and fixed
2//! or varying interest rates, what is the current value?
3//!
4//! For most common usages, we recommend the [`present_value_solution`](./fn.present_value_solution.html) function to provide a better debugging experience and additional features.
5//!
6//! If you have a more complicated use case which has varying rates per period, use the [`present_value_schedule_solution`](./fn.present_value_schedule_solution.html) function.
7//!
8// ! If you need to calculate the future value given a present value, a number of periods, and one
9// ! or more rates use [`future_value`] or related functions.
10// !
11// ! If you need to calculate a fixed rate given a present value, future value, and number of periods
12// ! use [`rate`] or related functions.
13// !
14// ! If you need to calculate the number of periods given a fixed rate and a present and future value
15// ! use [`periods`] or related functions.
16//! # Formulas
17//!
18//! ## Simple Compounding
19//!
20//! With simple compound interest, the present value is calculated with:
21//!
22//! > <img src="http://i.upmath.me/svg/present%5C_value%20%3D%20%7Bfuture%5C_value%20%5Cover%20(1%2Brate)%5E%7Bperiods%7D%7D" />
23//!
24//! Or using some more usual variable names:
25//!
26//! > <img src="http://i.upmath.me/svg/pv%20%3D%20%7Bfv%20%5Cover%20(1%2Br)%5En%7D" />
27//!
28//! `n` is often used for the number of periods, though it may be `t` for time if each period is
29//! assumed to be one year as in continuous compounding. `r` is the periodic rate, though this may
30//! appear as `i` for interest.
31//!
32//! Throughout this crate we use `pv` for present value and `fv` for future value. You may see these
33//! values called `P` for principal in some references.
34//!
35//! Within the [TvmSolution](././tvm_simple/struct.TvmSolution.html) struct we record the formula used for the particular calculation
36//! using both concrete values and symbols. For example if we calculated the present value of an
37//! investment that grows by 1.5% per month for 48 months using simple compounding and reaches a
38//! future value of $50,000 the solution struct would contain these fields:
39//! ```text
40//! formula: "24468.0848 = 50000.0000 / (1.015000 ^ 48)",
41//! symbolic_formula: "pv = fv / (1 + r)^n",
42//! ```
43//!
44//! ## Continuous Compounding
45//!
46//! With continuous compounding the formula is:
47//!
48//! > <img src="http://i.upmath.me/svg/present%5C_value%20%3D%20%7Bfuture%5C_value%20%5Cover%20e%5E%7Brate%20%5Ctimes%20periods%7D%7D" />
49//!
50//! or:
51//!
52//! > <img src="http:i.upmath.me/svg/pv%20%3D%20%7Bfv%20%5Cover%20e%5E%7Br%20%5Ctimes%20n%7D%7D" />
53//!
54//! With continuous compounding the period is assumed to be years and `t` (time) is often used as
55//! the variable name. Within this crate we stick with `n` for the number of periods so that it's
56//! easier to compare formulas when they're printed as simple text as part of the [TvmSolution](./struct.TvmSolution.html)
57//! struct. Taking the example above but switching to continuous compounding the struct would
58//! contain these fields:
59//! ```text
60//! formula: "24337.6128 = 50000.0000 / 2.718282^(0.015000 * 48)",
61//! symbolic_formula: "pv = fv / e^(rt)",
62//! ```
63
64use log::warn;
65
66use super::tvm::*;
67
68/// Returns the current value of a future amount using a fixed rate.
69///
70/// Related functions:
71/// * To calculate a present value with a fixed rate and return a struct that shows the formula and
72/// optionally produces the the period-by-period values use [`present_value_solution`](./fn.present_value_solution.html).
73/// * To calculate the present value if the rates vary by period use [`present_value_schedule`](./fn.present_value_schedule.html)
74/// or [`present_value_schedule_solution`](./fn.present_value_schedule_solution.html).
75///
76/// See the [present_value](./index.html) module page for the formulas.
77///
78/// # Arguments
79/// * `rate` - The rate at which the investment grows or shrinks per period,
80/// expressed as a floating point number. For instance 0.05 would mean 5% growth. Often appears as
81/// `r` or `i` in formulas.
82/// * `periods` - The number of periods such as quarters or years. Often appears as `n` or `t`.
83/// * `future_value` - The final value of the investment.
84/// * `continuous_compounding` - True for continuous compounding, false for simple compounding.
85///
86/// # Panics
87/// The call will fail if `rate` is less than -1.0 as this would mean the investment is
88/// losing more than its full value every period. It will fail also if the future value is zero as
89/// in this case there's no way to determine the present value.
90///
91/// # Examples
92/// Investment that grows month by month.
93/// ```
94/// use finance_solution::*;
95///
96/// // The investment will grow by 1.1% per month.
97/// let rate = 0.011;
98///
99/// // The investment will grow for 12 months.
100/// let periods = 12;
101///
102/// // The final value will be $50,000.
103/// let future_value = 50_000;
104///
105/// let continuous_compounding = false;
106///
107/// // Find the current value.
108/// let present_value = present_value(rate, periods, future_value, continuous_compounding);
109/// dbg!(&present_value);
110///
111/// // Confirm that the present value is correct to four decimal places (one hundredth of a cent).
112/// assert_rounded_4(-43_848.6409, present_value);
113/// ```
114/// Error case: The investment loses 105% per year. There's no way to work out what this means so
115/// the call to present_value() will panic.
116/// ```should_panic
117/// let rate = -1.05;
118/// let periods = 6;
119/// let present_value = -10_000.75;
120/// let continuous_compounding = false;
121/// let present_value = finance_solution::present_value(rate, periods, present_value, continuous_compounding);
122/// ```
123pub fn present_value<T>(rate: f64, periods: u32, future_value: T, continuous_compounding: bool) -> f64
124 where T: Into<f64> + Copy
125{
126 present_value_internal(rate, periods as f64, future_value.into(), continuous_compounding)
127}
128
129/// Calculates the current value of a future amount using a fixed rate and returns a struct
130/// with the inputs and the calculated value. This is used for keeping track of a collection of
131/// financial scenarios so that they can be examined later.
132///
133/// See the [present_value](./index.html) module page for the formulas.
134///
135/// Related functions:
136/// * For simply calculating a single present value using a fixed rate use [`present_value`](./fn.present_value.html).
137/// * To calculate the present value if the rates vary by period use [`present_value_schedule`](./fn.present_value_schedule.html)
138/// or [`present_value_schedule_solution`](./fn.present_value_schedule_solution.html).
139///
140/// # Arguments
141/// * `rate` - The rate at which the investment grows or shrinks per period,
142/// expressed as a floating point number. For instance 0.05 would mean 5% growth. Often appears as
143/// `r` or `i` in formulas.
144/// * `periods` - The number of periods such as quarters or years. Often appears as `n` or `t`.
145/// * `future_value` - The final value of the investment.
146/// * `continuous_compounding` - True for continuous compounding, false for simple compounding.
147///
148/// # Panics
149/// The call will fail if `rate` is less than -1.0 as this would mean the investment is
150/// losing more than its full value every period. It will fail also if the future value is zero as
151/// in this case there's no way to determine the present value.
152///
153/// # Examples
154/// Calculate a present value and examine the period-by-period values.
155/// ```
156/// use finance_solution::*;
157///
158/// // The rate is 8.45% per year.
159/// let rate = 0.0845;
160///
161/// // The investment will grow for six years.
162/// let periods = 6;
163///
164/// // The final value is $50,000.
165/// let future_value = 50_000;
166///
167/// let continuous_compounding = false;
168///
169/// // Calculate the present value and create a struct with the input values and
170/// // the formula used.
171/// let solution = present_value_solution(rate, periods, future_value, continuous_compounding);
172/// dbg!(&solution);
173///
174/// let present_value = solution.present_value();
175/// assert_rounded_4(present_value, -30_732.1303);
176///
177/// // Examine the formulas.
178/// let formula = solution.formula();
179/// dbg!(&formula);
180/// assert_eq!(formula, "-30732.1303 = -50000.0000 / (1.084500 ^ 6)");
181/// let symbolic_formula = solution.symbolic_formula();
182/// dbg!(&symbolic_formula);
183/// assert_eq!("pv = -fv / (1 + r)^n", symbolic_formula);
184///
185/// // Calculate the amount at the end of each period.
186/// let series = solution.series();
187/// dbg!(&series);
188/// ```
189/// Build a collection of present value calculations where the future value and periodic rate are
190/// fixed but the number of periods varies, then filter the results.
191/// ```
192/// // The rate is 0.9% per month.
193/// # use finance_solution::*;
194/// let rate = 0.009;
195///
196/// // The final value is $100,000.
197/// let future_value = 100_000;
198///
199/// let continuous_compounding = false;
200///
201/// // We'll keep a collection of the calculated present values along with their inputs.
202/// let mut scenarios = vec![];
203///
204/// // Calculate the present value for terms ranging from 1 to 36 months.
205/// for periods in 1..=36 {
206/// // Calculate the future value for this number of months and add the details to the
207/// // collection.
208/// scenarios.push(present_value_solution(rate, periods, future_value, continuous_compounding));
209/// }
210/// dbg!(&scenarios);
211/// assert_eq!(36, scenarios.len());
212///
213/// // Keep only the scenarios where the present value (which is negative) is greater than or
214/// // than or equal to -$80,000.
215/// scenarios.retain(|x| x.present_value() >= -80_000.00);
216/// dbg!(&scenarios);
217/// assert_eq!(12, scenarios.len());
218///
219/// // Find the range of months for the remaining scenarios.
220/// let min_months = scenarios.iter().map(|x| x.periods()).min().unwrap();
221/// let max_months = scenarios.iter().map(|x| x.periods()).max().unwrap();
222/// dbg!(min_months, max_months);
223/// assert_eq!(25, min_months);
224/// assert_eq!(36, max_months);
225///
226/// // Check the formulas for the first of the remaining scenarios.
227/// let formula = scenarios[0].formula();
228/// dbg!(&formula);
229/// assert_eq!("-79932.0303 = -100000.0000 / (1.009000 ^ 25)", formula);
230/// let symbolic_formula = scenarios[0].symbolic_formula();
231/// dbg!(&symbolic_formula);
232/// assert_eq!("pv = -fv / (1 + r)^n", symbolic_formula);
233///
234/// ```
235/// Error case: The investment loses 111% per year. There's no way to work out what this means so
236/// the call to present_value() will panic.
237/// ```should_panic
238/// # use finance_solution::*;
239/// let rate = -1.11;
240/// let periods = 12;
241/// let present_value = 100_000.85;
242/// let continuous_compounding = false;
243/// let present_value = present_value_solution(rate, periods, present_value, continuous_compounding);
244/// ```
245pub fn present_value_solution<T>(rate: f64, periods: u32, future_value: T, continuous_compounding: bool) -> TvmSolution
246 where T: Into<f64> + Copy
247{
248 present_value_solution_internal(rate, periods as f64, future_value.into(), continuous_compounding)
249}
250
251/// Calculates a present value based on rates that change for each period.
252///
253/// Related functions:
254/// * To calculate the present value with varying rates and return a struct that can produce the
255/// period-by-period values use [`present_value_schedule_solution`](./fn.present_value_schedule_solution.html).
256/// * If there is a single fixed rate use [present_value](./fn.present_value.html) or [present_value_solution](./fn.present_value_solution.html).
257///
258/// # Arguments
259/// * `rates` - A collection of rates, one for each period.
260/// * `future_value` - The ending value of the investment.
261///
262/// # Panics
263/// The call will fail if any of the rates is less than -1.0 as this would mean the investment is
264/// losing more than its full value every period. It will fail also if the future value is zero as
265/// in this case there's no way to determine the present value.
266///
267/// # Examples
268/// Calculate the present value of an investment whose rates vary by year.
269/// ```
270/// // The annual rate varies from -3.4% to 12.9%.
271/// let rates = [0.04, -0.034, 0.0122, 0.129, 8.5];
272///
273/// // The value of the investment after applying all of these periodic rates
274/// // will be $30_000.
275/// let future_value = 30_000.00;
276///
277/// // Calculate the present value.
278/// let present_value = finance_solution::present_value_schedule(&rates, future_value);
279/// dbg!(&present_value);
280/// ```
281pub fn present_value_schedule<T>(rates: &[f64], future_value: T) -> f64
282 where T: Into<f64> + Copy
283{
284 let periods = rates.len();
285 let future_value = future_value.into();
286
287 // Check the parameters including all of the provided rates.
288 for rate in rates {
289 check_present_value_parameters(*rate, periods as f64, future_value);
290 }
291
292 let mut present_value = -future_value;
293 for i in (0..periods).rev() {
294 present_value /= 1.0 + rates[i];
295 }
296
297 present_value
298}
299
300/// Calculates a present value based on rates that change for each period and returns a struct
301/// with the inputs and the calculated value.
302///
303/// Related functions:
304/// * To calculate the present value as a single number if the rates vary by period use
305/// [present_value_schedule](./fn.present_value_schedule.html).
306/// * If there is a single fixed rate use [present_value](./fn.present_value.html) or
307/// [present_value_solution](./fn.present_value_solution.html).
308///
309/// # Arguments
310/// * `rates` - A collection of rates, one for each period.
311/// * `future_value` - The ending value of the investment.
312///
313/// # Panics
314/// The call will fail if any of the rates is less than -1.0 as this would mean the investment is
315/// losing more than its full value every period. It will fail also if the future value is zero as
316/// in this case there's no way to determine the present value.
317///
318/// # Examples
319/// Calculate the value of an investment whose rates vary by year, then view only those periods
320/// where the rate is negative.
321/// ```
322/// use finance_solution::*;
323///
324/// // The quarterly rate varies from -0.5% to 4%.
325/// let rates = [0.04, 0.008, 0.0122, -0.005];
326///
327/// // The value of the investment after applying all of these periodic rates
328/// // will be $25_000.
329/// let future_value = 25_000.00;
330///
331/// // Calculate the present value and keep track of the inputs and the formula
332/// // in a struct.
333/// let solution = present_value_schedule_solution(&rates, future_value);
334/// dbg!(&solution);
335///
336/// let present_value = solution.present_value();
337/// assert_rounded_4(present_value, -23_678.6383);
338///
339/// // Calculate the value for each period.
340/// let series = solution.series();
341/// dbg!(&series);
342/// ```
343pub fn present_value_schedule_solution<T>(rates: &[f64], future_value: T) -> TvmScheduleSolution
344 where T: Into<f64> + Copy
345{
346 let present_value = present_value_schedule(rates, future_value);
347 TvmScheduleSolution::new(TvmVariable::PresentValue, rates, present_value, future_value.into())
348}
349
350pub(crate) fn present_value_internal(rate: f64, periods: f64, future_value: f64, continuous_compounding: bool) -> f64 {
351 check_present_value_parameters(rate, periods, future_value);
352 let present_value = if continuous_compounding {
353 -future_value / std::f64::consts::E.powf(rate * periods as f64)
354 } else {
355 -future_value / (1. + rate).powf(periods)
356 };
357 assert!(present_value.is_finite());
358 present_value
359}
360
361pub(crate) fn present_value_solution_internal(rate: f64, periods: f64, future_value: f64, continuous_compounding: bool) -> TvmSolution {
362 let present_value = present_value_internal(rate, periods, future_value, continuous_compounding);
363 let rate_multiplier = 1.0 + rate;
364 assert!(rate_multiplier >= 0.0);
365 let (formula, symbolic_formula) = if continuous_compounding {
366 let formula = format!("{:.4} = {:.4} / {:.6}^({:.6} * {})", present_value, -future_value, std::f64::consts::E, rate, periods);
367 let symbolic_formula = "pv = -fv / e^(rt)";
368 (formula, symbolic_formula)
369 } else {
370 let formula = format!("{:.4} = {:.4} / ({:.6} ^ {})", present_value, -future_value, rate_multiplier, periods);
371 let symbolic_formula = "pv = -fv / (1 + r)^n";
372 (formula, symbolic_formula)
373 };
374 TvmSolution::new_fractional_periods(TvmVariable::PresentValue, continuous_compounding, rate, periods, present_value, future_value, &formula, symbolic_formula)
375}
376
377fn check_present_value_parameters(rate: f64, _periods: f64, future_value: f64) {
378 assert!(rate.is_finite(), "The rate must be finite (not NaN or infinity)");
379 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.");
380 if rate.abs() > 1. {
381 warn!("You provided a periodic rate ({}) greater than 1. Are you sure you expect a {}% return?", rate, rate * 100.0);
382 }
383 assert!(future_value.is_finite(), "The future value must be finite (not NaN or infinity)");
384 assert!(future_value.is_normal(), "The future value is zero (or subnormal) so there is no way to calculate the present value.");
385}
386
387#[cfg(test)]
388mod tests {
389 use super::*;
390 use crate::*;
391
392 #[test]
393 fn test_present_value_schedule() {
394 let rates = [0.04, 0.07, -0.12, -0.03, 0.11];
395 let future_value = 100_000.25;
396
397 let present_value = present_value_schedule(&rates, future_value);
398 assert_rounded_4(-94843.2841, present_value);
399
400 let solution = present_value_schedule_solution(&rates, future_value);
401 assert_rounded_4(100000.2500, solution.future_value());
402 assert_rounded_4(-94843.2841, solution.present_value());
403
404 let series = solution.series();
405 assert_eq!(6, series.len());
406
407 let period = &series[0];
408 assert_eq!(0, period.period());
409 assert_rounded_6(0.0, period.rate());
410 assert_rounded_4(-present_value,period.value());
411
412 let period = &series[1];
413 assert_eq!(1, period.period());
414 assert_rounded_6(0.04, period.rate());
415 assert_rounded_4(98_637.0154,period.value());
416
417 let period = &series[2];
418 assert_eq!(2, period.period());
419 assert_rounded_6(0.07, period.rate());
420 assert_rounded_4(105_541.6065,period.value());
421
422 let period = &series[3];
423 assert_eq!(3, period.period());
424 assert_rounded_6(-0.12, period.rate());
425 assert_rounded_4(92_876.6137,period.value());
426
427 let period = &series[4];
428 assert_eq!(4, period.period());
429 assert_rounded_6(-0.03, period.rate());
430 assert_rounded_4(90_090.3153, period.value());
431
432 let period = &series[5];
433 assert_eq!(5, period.period());
434 assert_rounded_6(0.11, period.rate());
435 assert_rounded_4(100_000.2500, period.value());
436 }
437
438 /*
439 macro_rules! compare_to_excel {
440 ( $r:expr, $n:expr, $fv:expr, $pv_excel:expr, $pv_manual_simple:expr, $pv_manual_cont:expr ) => {
441 println!("$r = {}, $n = {}, $fv = {}, $pv_excel: {}, $pv_manual_simple = {}, $pv_manual_cont = {}", $r, $n, $fv, $pv_excel, $pv_manual_simple, $pv_manual_cont);
442 assert_approx_equal!($pv_excel, $pv_manual_simple);
443
444 let pv_calc_simple = present_value($r, $n, $fv, false);
445 println!("pv_calc_simple = {}", pv_calc_simple);
446 assert_approx_equal!($pv_excel, pv_calc_simple);
447
448 let pv_calc_cont = present_value($r, $n, $fv, true);
449 println!("pv_calc_cont = {}", pv_calc_cont);
450 assert_approx_equal!($pv_manual_cont, pv_calc_cont);
451
452 let ratio = pv_calc_cont / pv_calc_simple;
453 println!("ratio = {}", ratio);
454 assert!(ratio > 0.0);
455 assert!(ratio <= 1.0);
456 }
457 }
458 */
459
460 fn compare_to_excel (test_case: usize, r: f64, n: u32, fv: f64, pv_excel: f64, pv_manual_simple: f64, pv_manual_cont: f64) {
461 let display = false;
462
463 if display { println!("test_case = {}, r = {}, n = {}, fv = {}, pv_excel: {}, pv_manual_simple = {}, pv_manual_cont = {}", test_case, r, n, fv, pv_excel, pv_manual_simple, pv_manual_cont) };
464 assert_approx_equal!(pv_excel, pv_manual_simple);
465
466 let pv_calc_simple = present_value(r, n, fv, false);
467 if display { println!("pv_calc_simple = {}", pv_calc_simple) };
468 assert_approx_equal!(pv_excel, pv_calc_simple);
469
470 let pv_calc_cont = present_value(r, n, fv, true);
471 if display { println!("pv_calc_cont = {}", pv_calc_cont) };
472 assert_approx_equal!(pv_manual_cont, pv_calc_cont);
473
474 let ratio = pv_calc_cont / pv_calc_simple;
475 if display { println!("ratio = {}", ratio) };
476 assert!(ratio >= 0.0);
477 assert!(ratio <= 1.0);
478
479 // Solution with simple compounding.
480 let solution = present_value_solution(r, n, fv, false);
481 if display { dbg!(&solution); }
482 solution.invariant();
483 assert!(solution.calculated_field().is_present_value());
484 assert_eq!(false, solution.continuous_compounding());
485 assert_approx_equal!(r, solution.rate());
486 assert_eq!(n, solution.periods());
487 assert_approx_equal!(n as f64, solution.fractional_periods());
488 assert_approx_equal!(pv_excel, solution.present_value());
489 assert_approx_equal!(fv, solution.future_value());
490
491 // Solution with continuous compounding.
492 let solution = present_value_solution(r, n, fv, true);
493 if display { dbg!(&solution); }
494 solution.invariant();
495 assert!(solution.calculated_field().is_present_value());
496 assert!(solution.continuous_compounding());
497 assert_approx_equal!(r, solution.rate());
498 assert_eq!(n, solution.periods());
499 assert_approx_equal!(n as f64, solution.fractional_periods());
500 assert_approx_equal!(pv_manual_cont, solution.present_value());
501 assert_approx_equal!(fv, solution.future_value());
502
503 let rates = initialized_vector(n as usize, r);
504
505 // Schedule solution.
506 let solution = present_value_schedule_solution(&rates, fv);
507 if display { dbg!(&solution); }
508 solution.invariant();
509 assert!(solution.calculated_field().is_present_value());
510 assert_eq!(n, solution.periods());
511 assert_approx_equal!(pv_excel, solution.present_value());
512 assert_approx_equal!(fv, solution.future_value());
513 }
514
515 #[test]
516 fn test_present_value_against_excel() {
517 compare_to_excel(1, 0.01f64, 90, 1f64, -0.408391185151344f64, -0.408391185151344f64, -0.406569659740599f64);
518 compare_to_excel(2, -0.01f64, 85, -1.5f64, 3.52451788132823f64, 3.52451788132823f64, 3.50947027788899f64);
519 compare_to_excel(3, 0f64, 80, 2.25f64, -2.25f64, -2.25f64, -2.25f64);
520 compare_to_excel(4, 0.05f64, 75, -3.375f64, 0.0869113201859512f64, 0.0869113201859512f64, 0.0793723922640307f64);
521 compare_to_excel(5, -0.05f64, 70, 5.0625f64, -183.53236712846f64, -183.53236712846f64, -167.64697554088f64);
522 compare_to_excel(6, 0.01f64, 65, -7.59375f64, 3.97710447262579f64, 3.97710447262579f64, 3.96428511727897f64);
523 compare_to_excel(7, -0.01f64, 60, 11.390625f64, -20.8178501685176f64, -20.8178501685176f64, -20.7550719606981f64);
524 compare_to_excel(8, 0f64, 55, -17.0859375f64, 17.0859375f64, 17.0859375f64, 17.0859375f64);
525 compare_to_excel(9, 0.05f64, 50, 25.62890625f64, -2.23493614322574f64, -2.23493614322574f64, -2.10374873426328f64);
526 compare_to_excel(10, -0.05f64, 45, -38.443359375f64, 386.597546504632f64, 386.597546504632f64, 364.740438412197f64);
527 compare_to_excel(11, 0.01f64, 40, 57.6650390625f64, -38.7309044888379f64, -38.7309044888379f64, -38.6540316390219f64);
528 compare_to_excel(12, -0.01f64, 35, -86.49755859375f64, 122.962317182378f64, 122.962317182378f64, 122.745878432934f64);
529 compare_to_excel(13, 0f64, 30, 129.746337890625f64, -129.746337890625f64, -129.746337890625f64, -129.746337890625f64);
530 compare_to_excel(14, 0.05f64, 25, -194.619506835937f64, 57.4716797951039f64, 57.4716797951039f64, 55.7594222710607f64);
531 compare_to_excel(15, -0.05f64, 20, 291.929260253906f64, -814.33953749853f64, -814.33953749853f64, -793.546003343685f64);
532 compare_to_excel(16, 0.01f64, 15, -437.893890380859f64, 377.179672510109f64, 377.179672510109f64, 376.898764278606f64);
533 compare_to_excel(17, -0.01f64, 12, 656.840835571289f64, -741.033445550103f64, -741.033445550103f64, -740.585974095395f64);
534 compare_to_excel(18, 0f64, 10, -985.261253356933f64, 985.261253356933f64, 985.261253356933f64, 985.261253356933f64);
535 compare_to_excel(19, 0.05f64, 7, 1477.8918800354f64, -1050.31016709206f64, -1050.31016709206f64, -1041.45280575294f64);
536 compare_to_excel(20, -0.05f64, 5, -2216.8378200531f64, 2864.94240503709f64, 2864.94240503709f64, 2846.47610562283f64);
537 compare_to_excel(21, 0.01f64, 4, 3325.25673007965f64, -3195.50635796575f64, -3195.50635796575f64, -3194.87154873072f64);
538 compare_to_excel(22, -0.01f64, 3, -4987.88509511947f64, 5140.56501667989f64, 5140.56501667989f64, 5139.78881110503f64);
539 compare_to_excel(23, 0f64, 2, 7481.82764267921f64, -7481.82764267921f64, -7481.82764267921f64, -7481.82764267921f64);
540 compare_to_excel(24, 0.05f64, 1, -11222.7414640188f64, 10688.3252038274f64, 10688.3252038274f64, 10675.4019041389f64);
541 compare_to_excel(25, -0.05f64, 0, 16834.1121960282f64, -16834.1121960282f64, -16834.1121960282f64, -16834.1121960282f64);
542 }
543
544}