Skip to main content

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