1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
use std::collections::HashMap;
use std::fmt;
#[derive(Debug, Clone)]
pub struct Mortgage {
period: u32,
principal: f64,
i12: f64,
quota: f64,
quotas: u32,
}
impl fmt::Display for Mortgage {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{:3} | {:5} | {:4.2}\t{:.2}\t{:.2}\t{:.2}",
if self.period % 12 == 0 {
format!("Y{}", (self.period / 12) + 1)
} else {
"".to_string()
},
self.period,
self.quota,
self.quota_interest(),
self.quota_principal(),
self.principal
)
}
}
impl Mortgage {
pub fn new(principal: f64, i1: f64, years: u32) -> Self {
let quotas = years * 12;
let i12 = i1 / 12.0;
Mortgage {
period: 0,
principal,
i12,
quota: Self::quota(principal, i12, quotas),
quotas,
}
}
pub fn run(&mut self, updates: HashMap<u32, MortgageUpdate>) {
let principal = self.principal;
let topay_total = self.quota * self.quotas as f64;
let topay_interest = topay_total - principal;
let mut payed_total = 0.;
let mut payed_principal = 0.;
let mut payed_interest = 0.;
let mut payed_amortized = 0.;
println!("Año | Cuota | c\t\tIn\tAn\tCn");
while self.quotas > 0 && self.principal > 0. {
println!("{self}");
if let Some(update) = updates.get(&self.period) {
payed_amortized += self.update(update);
}
payed_total += self.quota;
payed_principal += self.quota_principal();
payed_interest += self.quota_interest();
self.step();
}
payed_total += payed_amortized;
println!("\n# A PRIORI");
println!(
"== Total a pagar: {:.2} ({} cap + {topay_interest:.2} int)",
topay_total, principal
);
println!(
"== Los intereses suponen un {:.2}% del total",
100. * topay_interest / topay_total
);
println!("\n# A POSTERIORI");
println!(
"== Total pagado: {:.2} ({:.2} cap + {:.2} int + {:.2} amortizado)",
payed_total, payed_principal, payed_interest, payed_amortized
);
println!(
"== Los intereses suponen un {:.2}% del total",
100. * payed_interest / payed_total
);
println!("\n");
}
fn update(&mut self, update: &MortgageUpdate) -> f64 {
print!(" [MORTGAGE UPDATE: ");
match update {
MortgageUpdate::Amortize(principal) => {
println!("{principal:.2} amortized to reduce quotas]");
self.principal -= principal;
self.quota = Self::quota(self.principal, self.i12, self.quotas);
*principal
}
}
}
fn quota(principal: f64, i12: f64, quotas: u32) -> f64 {
principal * i12 / (1.0 - (1.0 + i12).powi(-(quotas as i32)))
}
fn step(&mut self) {
self.period += 1;
self.quotas -= 1;
self.principal = (1.0 + self.i12) * self.principal - self.quota;
}
fn quota_interest(&self) -> f64 {
self.i12 * self.principal
}
fn quota_principal(&self) -> f64 {
self.quota - self.quota_interest()
}
}
pub enum MortgageUpdate {
Amortize(f64),
}
|