Struct TvmSolution

Source
pub struct TvmSolution { /* private fields */ }

Implementations§

Source§

impl TvmSolution

Source

pub fn series(&self) -> TvmSeries

Calculates the value of an investment after each period.

§Examples

Calculates the period-by-period details of a future value calculation. Uses future_value_solution.

// The initial investment is $10,000.12, the interest rate is 1.5% per month, and the
// investment will grow for 24 months using simple compounding.
let solution = finance_solution::future_value_solution(0.015, 24, 10_000.12, false);

// Calculate the value at the end of each period.
let series = solution.series();
dbg!(&series);

// Confirm that we have one entry for the initial value and one entry for each period.
assert_eq!(25, series.len());

// Print the period-by-period numbers in a formatted table.
series.print_table();

// Create a vector with every fourth period.
let filtered_series = series
    .iter()
    .filter(|x| x.period() % 4 == 0)
    .collect::<Vec<_>>();
dbg!(&filtered_series);
assert_eq!(7, filtered_series.len());

Calculate a present value with a fixed rate then examine the period-by-period values. Uses present_value_solution.

// The interest rate is 7.8% per year, the investment will grow for 10 years using simple
// compounding, and the final value will be 8_112.75.
let solution = finance_solution::present_value_solution(0.078, 10, 8_112.75, false);

// Calculate the value at the end of each period.
let series = solution.series();
dbg!(&series);

// Confirm that we have one entry for the present value, that is the
// initial value before any interest is applied, and one entry for each
// period.
assert_eq!(11, series.len());

// Create a reduced vector with every other period not including period 0,
// the initial state.
let filtered_series = series
    .iter()
    .filter(|x| x.period() % 2 == 0 && x.period() != 0)
    .collect::<Vec<_>>();
dbg!(&filtered_series);
assert_eq!(5, filtered_series.len());

Calculate a present value with varying rates then examine the period-by-period values. Uses present_value_schedule.

// The annual rate varies from -12% to 11%.
let rates = [0.04, 0.07, -0.12, -0.03, 0.11];

// The value of the investment after applying all of these periodic rates
// will be $100_000.25.
let future_value = 100_000.25;

// Calculate the present value and keep track of the inputs and the formula
// in a struct.
let solution = finance_solution::present_value_schedule_solution(&rates, future_value);
dbg!(&solution);

// Calculate the value at the end of each period.
let series = solution.series();
dbg!(&series);
// There is one entry for each period and one entry for period 0 containing
// the present value.
assert_eq!(6, series.len());

// Create a filtered list of periods, only those with a negative rate.
let filtered_series = series
    .iter()
    .filter(|x| x.rate() < 0.0)
    .collect::<Vec<_>>();
dbg!(&filtered_series);
assert_eq!(2, filtered_series.len());
Source

pub fn print_series_table(&self)

Prints a formatted table with the period-by-period details of a time-value-of-money calculation.

Money amounts are rounded to four decimal places, rates to six places, and numbers are formatted similar to Rust constants such as “10_000.0322”. For more control over formatting use [`TvmSolution::print_series_table_locale’].

§Examples
finance_solution::future_value_solution(0.045, 5, 10_000, false)
    .print_series_table();

Output:

period      rate        value
------  --------  -----------
     0  0.000000  10_000.0000
     1  0.045000  10_450.0000
     2  0.045000  10_920.2500
     3  0.045000  11_411.6612
     4  0.045000  11_925.1860
     5  0.045000  12_461.8194
Source

pub fn print_series_table_locale(&self, locale: &Locale, precision: usize)

Prints a formatted table with the period-by-period details of a time-value-of-money calculation.

For a simpler function that doesn’t require a locale use [`TvmSolution::print_series_table’].

§Arguments
  • locale - A locale constant from the num-format crate such as Locale::en for English or Locale::vi for Vietnamese. The locale determines the thousands separator and decimal separator.
  • precision - The number of decimal places for money amounts. Rates will appear with at least six places regardless of this argument.
§Examples
// English formatting with "," for the thousands separator and "." for the decimal
// separator.
let locale = finance_solution::num_format::Locale::en;

// Show money amounts to two decimal places.
let precision = 2;

finance_solution::future_value_solution(0.11, 4, 5_000, false)
    .print_series_table_locale(&locale, precision);

Output:

period      rate     value
------  --------  --------
     0  0.000000  5,000.00
     1  0.110000  5,550.00
     2  0.110000  6,160.50
     3  0.110000  6,838.16
     4  0.110000  7,590.35
Source

pub fn calculated_field(&self) -> &TvmVariable

Returns a variant of TvmVariable showing which value was calculated, either the periodic rate, number of periods, present value, or future value. To test for the enum variant use functions like TvmVariable::is_rate.

§Examples
// Calculate the future value of $25,000 that grows at 5% for 12 yeors.
let solution = finance_solution::future_value_solution(0.05, 12, 25_000, false);
assert!(solution.calculated_field().is_future_value());
Source

pub fn continuous_compounding(&self) -> bool

Returns true if the value is compounded continuously rather than period-by-period.

Source

pub fn rate(&self) -> f64

Returns the periodic rate which is a calculated value if this TvmSolution struct is the result of a call to rate_solution and otherwise is one of the input values.

Source

pub fn periods(&self) -> u32

Returns the number of periods as a whole number. This is a calculated value if this TvmSolution struct is the result of a call to periods_solution and otherwise it’s one of the input values. If the value was calculated the true result may not have been a whole number so this is that number rounded away from zero.

Source

pub fn fractional_periods(&self) -> f64

Returns the number of periods as a floating point number. This is a calculated value if this TvmSolution struct is the result of a call to periods_solution and otherwise it’s one of the input values.

Source

pub fn present_value(&self) -> f64

Returns the present value which is a calculated value if this TvmSolution struct is the result of a call to present_value_solution and otherwise is one of the input values.

Source

pub fn future_value(&self) -> f64

Returns the future value which is a calculated value if this TvmSolution struct is the result of a call to future_value_solution and otherwise is one of the input values.

Source

pub fn formula(&self) -> &str

Returns a text version of the formula used to calculate the result which may have been the periodic rate, number of periods, present value, or future value depending on which function was called. The formula includes the actual values rather than variable names. For the formula with variables such as r for rate call symbolic_formula.

Source

pub fn symbolic_formula(&self) -> &str

Returns a text version of the formula used to calculate the result which may have been the periodic rate, number of periods, present value, or future value depending on which function was called. The formula uses variables such as n for the number of periods. For the formula with the actual values rather than variables call formula.

Source

pub fn rate_solution( &self, continuous_compounding: bool, compounding_periods: Option<u32>, ) -> TvmSolution

Source

pub fn periods_solution(&self, continuous_compounding: bool) -> TvmSolution

Source

pub fn present_value_solution( &self, continuous_compounding: bool, compounding_periods: Option<u32>, ) -> TvmSolution

Source

pub fn future_value_solution( &self, continuous_compounding: bool, compounding_periods: Option<u32>, ) -> TvmSolution

Source

pub fn present_value_vary_compounding_periods( &self, compounding_periods: &[u32], include_continuous_compounding: bool, ) -> ScenarioList

Returns a struct with a set of what-if scenarios for the present value needed with a variety of compounding periods.

§Arguments
  • compounding_periods - The compounding periods to include in the scenarios. The result will have a computed present value for each compounding period in this list.
  • include_continuous_compounding - If true, adds one scenario at the end of the results with continuous compounding instead of a given number of compounding periods.
§Examples

For a more detailed example with a related function see future_value_vary_compounding_periods

// Calculate the future value of an investment that starts at $83.33 and grows 20% in one
// year using simple compounding. Note that we're going to examine how the present value
// varies by the number of compounding periods but we're starting with a future value
// calculation. It would have been fine to start with a rate, periods, or present value
// calculation as well. It just depends on what information we have to work with.
let solution = finance_solution::future_value_solution(0.20, 1, -83.333, false);
dbg!(&solution);

// The present value of $83.33 gives us a future value of about $100.00.
finance_solution::assert_rounded_2!(100.00, solution.future_value());

// We'll experiment with compounding annually, quarterly, monthly, weekly, and daily.
let compounding_periods = [1, 4, 12, 52, 365];

// Add a final scenario with continuous compounding.
let include_continuous_compounding = true;

// Compile a list of the present values needed to arrive at the calculated future value of $100
// each of the above compounding periods as well a continous compounding.
let scenarios = solution.present_value_vary_compounding_periods(&compounding_periods, include_continuous_compounding);
dbg!(&scenarios);

// Print the results in a formatted table.
scenarios.print_table();

Output from the last line:

Periods  Present Value
-------  -------------
      1        83.3330
      4        82.2699
     12        82.0078
     52        81.9042
    365        81.8772
    inf        81.8727

As we compound the interest more frequently we need a slightly smaller initial value to reach the same final value of $100 in one year. With more frequent compounding the required initial value approaches $81.87, the present value needed with continuous compounding.

If we plot this using between 1 and 12 compounding periods it’s clear that the required present value drops sharply if we go from compounding annually to compounding semiannually or quarterly but then is affected less and less as we compound more frequently:

Source

pub fn future_value_vary_compounding_periods( &self, compounding_periods: &[u32], include_continuous_compounding: bool, ) -> ScenarioList

Returns a struct with a set of what-if scenarios for the future value of an investment given a variety of compounding periods.

§Arguments
  • compounding_periods - The compounding periods to include in the scenarios. The result will have a computed future value for each compounding period in this list.
  • include_continuous_compounding - If true, adds one scenario at the end of the results with continuous compounding instead of a given number of compounding periods.
§Examples
// The interest rate is 5% per quarter.
let rate = 0.05;

// The interest will be applied once per quarter for one year.
let periods = 4;

// The starting value is $100.00.
let present_value = 100;

let continuous_compounding = false;

let solution = finance_solution::future_value_solution(rate, periods, present_value, continuous_compounding);
dbg!(&solution);

// We'll experiment with compounding annually, quarterly, monthly, weekly, and daily.
let compounding_periods = [1, 4, 12, 52, 365];

// Add a final scenario with continuous compounding.
let include_continuous_compounding = true;

// Compile a list of the future values with each of the above compounding periods as well as
// continous compounding.
let scenarios = solution.future_value_vary_compounding_periods(&compounding_periods, include_continuous_compounding);
// The description in the `setup` field states that the rate is 20% since that's 5% times the
// number of periods in the original calculation. The final entry has `input: inf` indicating
// that we used continuous compounding.
dbg!(&scenarios);

// Print the results in a formatted table.
scenarios.print_table();

Output:

&solution = FutureValueSolution {
    tvm_solution: TvmSolution {
    calculated_field: FutureValue,
    continuous_compounding: false,
    rate: 0.05,
    periods: 4,
    fractional_periods: 4.0,
    present_value: 100.0,
    future_value: 121.55062500000003,
    formula: "121.5506 = 100.0000 * (1.050000 ^ 4)",
    symbolic_formula: "fv = pv * (1 + r)^n",
},

&scenarios = ScenarioList {
    setup: "Compare future values with different compounding periods where the rate is 0.200000 and the present value is 100.0000.",
    input_variable: Periods,
    output_variable: FutureValue,
    entries: [
        { input: 1, output: 120.0000 },
        { input: 4, output: 121.5506 },
        { input: 12, output: 121.9391 },
        { input: 52, output: 122.0934 },
        { input: 365, output: 122.1336 },
        { input: inf, output: 122.1403 },
    ],
}

Periods  Future Value
-------  ------------
      1      120.0000
      4      121.5506
     12      121.9391
     52      122.0934
    365      122.1336
    inf      122.1403

With the same interest rate and overall time period, an amount grows faster if we compound the interest more frequently. As the number of compounding periods grows the future value approaches the limit of $122.14 that we get with continuous compounding.

As a chart it looks like this, here using only 1 through 12 compounding periods for clarity:

Source

pub fn print_ab_comparison(&self, other: &TvmSolution)

Source

pub fn print_ab_comparison_locale( &self, other: &TvmSolution, locale: &Locale, precision: usize, )

Trait Implementations§

Source§

impl Clone for TvmSolution

Source§

fn clone(&self) -> TvmSolution

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for TvmSolution

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl PartialEq for TvmSolution

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.