si_scale/base.rs
1//! Defines the `Base` struct and methods.
2
3/// Represents the base for units [Prefix](crate::prefix::Prefix).
4///
5#[derive(Debug, PartialEq, Eq)]
6pub enum Base {
7 /// The most common base, where 1 k means `1000,` 1 M means `1000^2`, ...
8 B1000,
9 /// A very common base for bibytes, where 1 kiB means `1024`, 1 MiB means
10 /// `1024 * 1024`, ...
11 B1024,
12}
13
14impl Base {
15 /// Using `floor()`, returns the closest integer exponent to represent the
16 /// provided value `x` in the self `Base`.
17 ///
18 /// The returned integer exponent is a multiple of 3 in order to match the
19 /// prefixes' exponents.
20 ///
21 /// # Example
22 ///
23 /// ```
24 /// use si_scale::base::Base;
25 ///
26 /// let x: f32 = 5.4e4;
27 /// let actual = Base::B1000.integral_exponent_for(x);
28 /// assert_eq!(actual, 3); // 1e3
29 ///
30 /// let x: f64 = -5.4e-4;
31 /// let actual = Base::B1000.integral_exponent_for(x);
32 /// assert_eq!(actual, -6); // 1e-6
33 /// ```
34 ///
35 pub fn integral_exponent_for<F>(&self, x: F) -> i32
36 where
37 F: Into<f64>,
38 {
39 let x: f64 = x.into();
40 if x == 0.0 {
41 return 0;
42 }
43 match self {
44 Self::B1000 => (x.abs().log10() / 3f64).floor() as i32 * 3,
45 Self::B1024 => (x.abs().log2() / 10f64).floor() as i32 * 3,
46 }
47 }
48
49 /// This helper function returns a `f64` scaling factor for the mantissa,
50 /// obtained by raising self to the power of the provided `exponent`
51 /// divided by 3.
52 ///
53 /// # Example
54 ///
55 /// ```
56 /// use si_scale::base::Base;
57 ///
58 /// assert_eq!(Base::B1000.pow(9), 1e9);
59 /// assert_eq!(Base::B1024.pow(3), 1024f64)
60 /// ```
61 ///
62 pub fn pow(&self, exponent: i32) -> f64 {
63 match self {
64 Self::B1000 => 1000f64.powf(exponent as f64 / 3f64),
65 Self::B1024 => 1024f64.powf(exponent as f64 / 3f64),
66 }
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 #[test]
75 fn exponent_of_zero_is_zero() {
76 assert_eq!(0, Base::B1000.integral_exponent_for(0.0));
77 assert_eq!(0, Base::B1000.integral_exponent_for(-0.0));
78
79 assert_eq!(0, Base::B1024.integral_exponent_for(0.0));
80 assert_eq!(0, Base::B1024.integral_exponent_for(-0.0));
81 }
82}