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
/// Represents the base for units [Prefix](crate::prefix::Prefix).
///
#[derive(Debug, PartialEq)]
pub enum Base {
    /// The most common base, where 1 k means `1000,` 1 M means `1000^2`, ...
    B1000,
    /// A very common base for bibytes, where 1 kiB means `1024`, 1 MiB means
    /// `1024 * 1024`, ...
    B1024,
}

impl Base {
    /// Using `floor()`, returns the closest integer exponent to represent the
    /// provided value `x` in the self `Base`.
    ///
    /// The returned integer exponent is a multiple of 3 in order to match the
    /// prefixes' exponents.
    ///
    /// # Example
    ///
    /// ```
    /// use si_scale::base::Base;
    ///
    /// let x: f32  = 5.4e4;
    /// let actual = Base::B1000.integral_exponent_for(x);
    /// assert_eq!(actual, 3);  // 1e3
    ///
    /// let x: f64  = -5.4e-4;
    /// let actual = Base::B1000.integral_exponent_for(x);
    /// assert_eq!(actual, -6);  // 1e-6
    /// ```
    ///
    pub fn integral_exponent_for<F>(&self, x: F) -> i32
    where
        F: Into<f64>,
    {
        let x: f64 = x.into();
        match self {
            Self::B1000 => (x.abs().log10() / 3f64).floor() as i32 * 3,
            Self::B1024 => (x.abs().log2() / 10f64).floor() as i32 * 3,
        }
    }

    /// This helper function returns a `f64` scaling factor for the mantissa,
    /// obtained by raising self to the power of the provided `exponent`
    /// divided by 3.
    ///
    /// # Example
    ///
    /// ```
    /// use si_scale::base::Base;
    ///
    /// assert_eq!(Base::B1000.pow(9), 1e9);
    /// assert_eq!(Base::B1024.pow(3), 1024f64)
    /// ```
    ///
    pub fn pow(&self, exponent: i32) -> f64 {
        match self {
            Self::B1000 => 1000f64.powf(exponent as f64 / 3f64),
            Self::B1024 => 1024f64.powf(exponent as f64 / 3f64),
        }
    }
}