execution_time/traits/
round_float.rs

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
/// Trait for rounding floating-point numbers to a specified number of decimal places.
pub trait RoundFloat<T> {
    /// Rounds the floating-point number to the given number of decimal places.
    ///
    /// # Arguments
    ///
    /// * `decimal_places` - The number of decimal places to round to.
    ///
    /// # Returns
    ///
    /// The rounded floating-point number.
    fn round_float(self, decimal_places: T) -> Self
    where
        Self: std::marker::Sized; // This trait is object safe
}

impl<T> RoundFloat<T> for f64
where
    i32: TryFrom<T>,
    <i32 as TryFrom<T>>::Error: std::fmt::Display,
{
    fn round_float(self, decimal_places: T) -> f64 {
        match i32::try_from(decimal_places) {
            Ok(dec) => {
                if dec <= 0 || self == 0.0 {
                    self.round()
                } else {
                    let multiplier: f64 = 10.0_f64.powi(dec);
                    (self * multiplier).round() / multiplier
                }
            }
            Err(why) => {
                let t = std::any::type_name::<T>();
                eprintln!("fn round_float() for f64: {self}");
                eprintln!("Error converting decimal places from type {t} to i32.");
                panic!("Invalid Decimal Places: {why}")
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_round_positive_decimal_places() {
        // Test rounding to 2 decimal places
        let num: f64 = 5.22501;
        assert_eq!(num.round_float(2), 5.23);

        // Test rounding to 3 decimal places
        let num = 12.34567;
        assert_eq!(num.round_float(3), 12.346);

        // Test rounding to 1 decimal place
        let num = 7.89;
        assert_eq!(num.round_float(1), 7.9);

        // Test rounding to a greater number of decimal places than available.
        let num = 1.2;
        assert_eq!(num.round_float(4), 1.2);

        //Test with a negative number
        let num = -2.789;
        assert_eq!(num.round_float(2), -2.79)
    }

    #[test]
    fn test_round_zero_decimal_places() {
        // Test rounding to 0 decimal places (should round to nearest whole number)
        let num = 3.6;
        assert_eq!(num.round_float(0), 4.0);

        // Test rounding to 0 decimal places (should round to nearest whole number)
        let num = 3.4;
        assert_eq!(num.round_float(0), 3.0);
    }

    #[test]
    fn test_round_negative_decimal_places() {
        // Test rounding with negative decimal places which should be equivalent to round()
        let num = 123.456;
        assert_eq!(num.round_float(-1), 123.0);

        // Test rounding with negative decimal places with a negative number
        let num = -123.456;
        assert_eq!(num.round_float(-2), -123.0);

        // Test rounding with negative decimal places
        let num = 123.56;
        assert_eq!(num.round_float(-1), 124.0);
    }

    #[test]
    fn test_round_with_zero() {
        // Test with zero number, should return 0
        let num = 0.0;
        assert_eq!(num.round_float(2), 0.0);
        assert_eq!(num.round_float(0), 0.0);
        assert_eq!(num.round_float(-2), 0.0);
    }
}