Skip to main content

scratch_test_value/math/
exp.rs

1use crate::{QuirkSink, SNumber, quirks::SNumberToFloatQ};
2
3impl SNumber {
4    pub fn q_exp<Q>(&self, sink: &mut Q) -> SNumber
5    where
6        Q: QuirkSink<SNumberToFloatQ>,
7    {
8        SNumber::Float(self.q_as_float_nan_is_zero(sink).exp())
9    }
10
11    pub fn q_ln<Q>(&self, sink: &mut Q) -> SNumber
12    where
13        Q: QuirkSink<SNumberToFloatQ>,
14    {
15        Self::Float(self.q_as_float_nan_is_zero(sink).ln())
16    }
17
18    pub fn q_log10<Q>(&self, sink: &mut Q) -> SNumber
19    where
20        Q: QuirkSink<SNumberToFloatQ>,
21    {
22        Self::Float(self.q_as_float_nan_is_zero(sink).log10())
23    }
24
25    /// This computes `10^value` where value is the number in `self`
26    ///
27    /// If the stored number is an integer, the exponent can losslessly
28    /// be interpreted as [`u32`] and the result fits into [`i64`]
29    /// the integer function [`i64::checked_pow`] is used.
30    ///
31    /// Otherwise [`f64::powf`] is used, `NaN` will be treated as 0.
32    pub fn q_power_of_10<Q>(&self, sink: &mut Q) -> SNumber
33    where
34        Q: QuirkSink<SNumberToFloatQ>,
35    {
36        if let Self::Int(i) = self
37            && let Ok(exponent) = u32::try_from(*i)
38            && let Some(result) = 10_i64.checked_pow(exponent)
39        {
40            Self::Int(result)
41        } else {
42            Self::Float(10.0_f64.powf(self.q_as_float_nan_is_zero(sink)))
43        }
44    }
45
46    #[allow(unused)]
47    pub(crate) fn exp(&self) -> SNumber {
48        self.q_exp(&mut ())
49    }
50    #[allow(unused)]
51    pub(crate) fn ln(&self) -> SNumber {
52        self.q_ln(&mut ())
53    }
54    #[allow(unused)]
55    pub(crate) fn power_of_10(&self) -> SNumber {
56        self.q_power_of_10(&mut ())
57    }
58    #[allow(unused)]
59    pub(crate) fn log10(&self) -> SNumber {
60        self.q_log10(&mut ())
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use crate::SNumber;
67
68    #[test]
69    fn test_ln_special() {
70        assert_eq!(SNumber::NEG_INFINITY, SNumber::Float(0.0).ln());
71        assert_eq!(SNumber::POS_ZERO, SNumber::Float(1.0).ln());
72        assert_eq!(SNumber::NEG_ZERO, SNumber::Float(1.0).ln());
73        assert_eq!(SNumber::INFINITY, SNumber::INFINITY.ln());
74        assert_eq!(SNumber::NAN, SNumber::NEG_INFINITY.ln());
75        assert_eq!(SNumber::NEG_INFINITY, SNumber::NAN.ln());
76    }
77
78    #[test]
79    fn test_log10_special() {
80        assert_eq!(SNumber::NEG_INFINITY, SNumber::Float(0.0).log10());
81        assert_eq!(SNumber::POS_ZERO, SNumber::Float(1.0).log10());
82        assert_eq!(SNumber::NEG_ZERO, SNumber::Float(1.0).log10());
83        assert_eq!(SNumber::INFINITY, SNumber::INFINITY.log10());
84        assert_eq!(SNumber::NAN, SNumber::NEG_INFINITY.log10());
85        assert_eq!(SNumber::NEG_INFINITY, SNumber::NAN.log10());
86    }
87
88    #[test]
89    fn test_exp_special() {
90        assert_eq!(SNumber::Int(1), SNumber::Float(0.0).exp());
91        assert_eq!(SNumber::INFINITY, SNumber::INFINITY.exp());
92        assert_eq!(SNumber::POS_ZERO, SNumber::NEG_INFINITY.exp());
93        assert_eq!(SNumber::NEG_ZERO, SNumber::NEG_INFINITY.exp());
94        assert_eq!(SNumber::Float(1.0), SNumber::NAN.exp());
95        assert_eq!(SNumber::Int(1), SNumber::NAN.exp());
96
97        assert_eq!(SNumber::INFINITY, SNumber::Float(10000.0).exp());
98    }
99
100    #[test]
101    fn test_10_to_special() {
102        assert_eq!(SNumber::Int(1), SNumber::Float(0.0).power_of_10());
103        assert_eq!(SNumber::INFINITY, SNumber::INFINITY.power_of_10());
104        assert_eq!(SNumber::POS_ZERO, SNumber::NEG_INFINITY.power_of_10());
105        assert_eq!(SNumber::NEG_ZERO, SNumber::NEG_INFINITY.power_of_10());
106        assert_eq!(SNumber::Float(1.0), SNumber::NAN.power_of_10());
107        assert_eq!(SNumber::Int(1), SNumber::NAN.power_of_10());
108    }
109}