h_math/finance.rs
1
2
3
4
5
6
7
8// ------------------------------------ Finance ------------------------------------
9
10
11/// This trait calculates the return on investment (ROI) given a new value. The ROI is calculated as ((new_value - original_value) / original_value) * 100, where original_value is the value of the investment before the change. The function will return the ROI as a percentage. For example, if the original value of an investment is 100 and the new value is 150, the ROI would be ((150 - 100) / 100) * 100 = 50%, indicating a 50% return on the original investment.
12/// Example usage:
13/// let original_value = 100.0;
14/// let new_value = 150.0;
15/// let roi = original_value.h_return_on_investment(new_value);
16/// The result will be 50.0, because the return on investment is ((150 - 100) / 100) * 100 = 50%.
17pub trait ROI {
18 fn h_return_on_investment(&self, new_value: f64) -> f64;
19}
20
21impl<T> ROI for T
22where
23 T: Copy + Into<f64>,
24{
25 fn h_return_on_investment(&self, new_value: f64) -> f64 {
26 let start = (*self).into();
27 (new_value - start) / start * 100.0
28 }
29}
30
31/// This trait calculates the discounted price of an item given a percentage decrease.
32/// The discounted price is calculated as original_price * (1 - decrease_percent / 100),
33/// where original_price is the initial price of the item,
34/// and decrease_percent is the percentage by which the price is reduced.
35/// The function will return the discounted price. For example, if the original price of an item is 100,
36/// and the decrease percent is 20, the discounted price would be 100 * (1 - 20 / 100) = 80,
37/// indicating that the item now costs 80 after a 20% discount.
38pub trait DiscountedPrice {
39 fn h_decreased_price(&self, decrease_percent: f64) -> f64;
40}
41
42impl<T> DiscountedPrice for T
43where
44 T: Copy + Into<f64>,
45{
46 fn h_decreased_price(&self, decrease_percent: f64) -> f64 {
47 let percent_discount_opposite: f64 = 1.0 - decrease_percent / 100.0;
48 percent_discount_opposite * (*self).into()
49 }
50}
51
52
53/// This trait calculates the increased price of an item given a percentage increase.
54/// The increased price is calculated as original_price * (1 + increase_percent / 100),
55/// where original_price is the initial price of the item, and increase_percent is the percentage
56/// by which the price is increased.
57/// The function will return the increased price. For example, if the original price of an item is 100,
58/// and the increase percent is 20, the increased price would be 100 * (1 + 20 / 100) = 120,
59/// indicating that the item now costs 120 after a 20% increase.
60pub trait IncreasedPrice {
61 fn h_increased_price(&self, increase_percent: f64) -> f64;
62}
63
64impl<T> IncreasedPrice for T
65where
66 T: Copy + Into<f64>,
67{
68 fn h_increased_price(&self, increase_percent: f64) -> f64 {
69 let percent_increas_plus_one: f64 = 1.0 + increase_percent / 100.0;
70 percent_increas_plus_one * (*self).into()
71 }
72}
73
74
75
76/// this trait calculates the percentage increase from an original value to a new value.
77/// The percentage increase is calculated as ((new_value - original_value) / original_value) * 100,
78/// where original_value is the initial value before the increase.
79/// The function will return the percentage increase as a positive value. For example,
80/// if the original value is 100 and the new value is 150, the percentage increase would be
81/// ((150 - 100) / 100) * 100 = 50%, indicating a 50% increase from the original value.
82/// Example usage:
83/// let original_value = 100.0;
84/// let new_value = 150.0;
85///
86/// let percent_increase = original_value.h_increase_percent_from_original(new_value);
87/// The result will be 50.0, because the percentage increase is ((150 -
88pub trait IncreasePercentFromOriginal {
89 fn h_increase_percent_from_original(&self, new_value: f64) -> f64;
90}
91
92impl<T> IncreasePercentFromOriginal for T
93where
94 T: Copy + Into<f64>,
95{
96 fn h_increase_percent_from_original(&self, new_value: f64) -> f64 {
97 let original_value = (*self).into();
98 ((new_value - original_value) / original_value) * 100.0
99 }
100}
101
102
103/// This trait calculates the percentage decrease from an original value to a new value.
104/// The percentage decrease is calculated as ((original_value - new_value) / original_value) * 100,
105/// where original_value is the initial value before the decrease.
106/// The function will return the percentage decrease as a positive value.
107/// For example, if the original value is 100 and the new value is 80, the percentage decrease would be
108/// ((100 - 80) / 100) * 100 = 20%, indicating a 20% decrease from the original value.
109/// Example usage:
110/// let original_value = 100.0;
111/// let new_value = 80.0;
112/// let percent_decrease = original_value.h_decrease_percent_from_original(new_value);
113/// The result will be 20.0, because the percentage decrease is ((100 - 80) / 100) * 100 = 20%.
114pub trait DecreasePercentFromOriginal {
115 fn h_decrease_percent_from_original(&self, new_value: f64) -> f64;
116}
117
118impl<T> DecreasePercentFromOriginal for T
119where
120 T: Copy + Into<f64>,
121{
122 fn h_decrease_percent_from_original(&self, new_value: f64) -> f64 {
123 let original_value = (*self).into();
124 ((original_value - new_value) / original_value) * 100.0
125 }
126}
127
128
129
130/// This trait calculates the total tax paid based on a set of tax brackets.
131///Each tax bracket is defined by a start income, an end income, and a tax percentage.
132/// The function will iterate through the tax brackets and calculate the tax paid for
133/// each bracket based on the income and the corresponding tax rate.
134/// The total tax paid will be the sum of the taxes calculated for each bracket. For example,
135/// if the income is 50,000 and there are two tax brackets: (0, 30,000, 10%) and (30,000, 100,000, 20%),
136/// the total tax paid would be (30,000 * 10%) + (20,000 * 20%) = 3,000 + 4,000 = 7,000.
137///
138/// it returns None if the income is less than or equal to 0,
139/// if any tax percentage is greater than 100,
140/// or if the tax brackets are not properly ordered (i.e., i
141/// f the start of a bracket is greater than the end of the previous bracket).
142pub trait BracketTaxPaid<Start, End, Percent>
143where
144 Start: Copy + Into<f64>,
145 End: Copy + Into<f64>,
146 Percent: Copy + Into<f64>,
147{
148 fn h_bracket_tax_paid(&self, brackets: Vec<(Start, End, Percent)>) -> Option<f64>;
149}
150
151impl<V, Start, End, Percent> BracketTaxPaid<Start, End, Percent> for V
152where
153 V: Copy + PartialEq + Into<f64>,
154 Start: Copy + PartialEq + Into<f64>,
155 End: Copy + PartialEq + Into<f64>,
156 Percent: Copy + PartialEq + Into<f64>,
157{
158 fn h_bracket_tax_paid(&self, brackets: Vec<(Start, End, Percent)>) -> Option<f64> {
159 if (*self).into() <= 0.0 {
160 return None;
161 }
162
163 let mut prev_item: Option<&(Start, End, Percent)> = None;
164 let income: f64 = (*self).into();
165 let mut sum: f64 = 0.0;
166
167 for item in &brackets {
168 if item.2.into() > 100.0 {
169 return None;
170 }
171 if let Some(prev) = prev_item {
172 if prev.0.into() > item.0.into() || prev.1.into() >= item.1.into() {
173 return None;
174 }
175 }
176 prev_item = Some(item);
177
178 let start: f64 = item.0.into() - 1.0;
179 let end: f64 = item.1.into();
180 let rate: f64 = item.2.into() / 100.0;
181
182 if income <= start {
183 break;
184 }
185
186 let taxable = end.min(income) - start;
187 sum += taxable * rate;
188
189 if income < end {
190 break;
191 }
192 }
193 return Some(sum);
194 }
195}
196
197
198#[cfg(test)]
199mod tests {
200 use super::*;
201
202 #[test]
203 fn test_roi() {
204 assert_eq!(100.0.h_return_on_investment(150.0), 50.0);
205 assert_eq!(200.0.h_return_on_investment(180.0), -10.0);
206 }
207
208 #[test]
209 fn test_decreased_price() {
210 assert_eq!(100.0.h_decreased_price(20.0), 80.0);
211 assert_eq!(200.0.h_decreased_price(10.0), 180.0);
212 }
213
214 #[test]
215 fn test_increased_price() {
216 assert!((100.0.h_increased_price(20.0) - 120.0).abs() < 1e-10);
217 assert!((200.0.h_increased_price(10.0) - 220.0).abs() < 1e-10);
218 }
219
220 #[test]
221 fn test_increase_percent_from_original() {
222 assert_eq!(100.0.h_increase_percent_from_original(150.0), 50.0);
223 assert_eq!(200.0.h_increase_percent_from_original(180.0), -10.0);
224 }
225
226 #[test]
227 fn test_decrease_percent_from_original() {
228 assert_eq!(100.0.h_decrease_percent_from_original(80.0), 20.0);
229 assert_eq!(200.0.h_decrease_percent_from_original(220.0), -10.0);
230 }
231
232 #[test]
233 fn test_bracket_tax_paid() {
234 // full brackets
235 // 100 income, brackets: 1-50 at 10%, 51-100 at 20%
236 // 50 * 0.10 = 5.0, 50 * 0.20 = 10.0, total = 15.0
237 let brackets = vec![(1, 50, 10), (51, 100, 20)];
238 assert_eq!(100_i32.h_bracket_tax_paid(brackets), Some(15.0));
239
240 // partial bracket
241 // 75 income, brackets: 1-50 at 10%, 51-100 at 20%
242 // 50 * 0.10 = 5.0, 25 * 0.20 = 5.0, total = 10.0
243 let brackets = vec![(1, 50, 10), (51, 100, 20)];
244 assert_eq!(75_i32.h_bracket_tax_paid(brackets), Some(10.0));
245
246 // zero income returns None
247 let brackets = vec![(1, 50, 10), (51, 100, 20)];
248 assert_eq!(0_i32.h_bracket_tax_paid(brackets), None);
249
250 // invalid percent returns None
251 let brackets = vec![(1, 50, 101)];
252 assert_eq!(100_i32.h_bracket_tax_paid(brackets), None);
253}
254
255}
256
257
258
259
260
261
262