num_bigfloat/ops/
log.rs

1//! Logarithms.
2
3use crate::defs::BigFloatNum;
4use crate::defs::Error;
5use crate::defs::DECIMAL_BASE;
6use crate::defs::DECIMAL_PARTS;
7use crate::defs::DECIMAL_POSITIONS;
8
9impl BigFloatNum {
10    /// Returns natural logarithm of a number.
11    ///
12    /// # Errors
13    ///
14    /// ExponentOverflow - when result is too big.
15    ///
16    /// InvalidArgument - when `self` is negative or zero.
17    pub fn ln(&self) -> Result<Self, Error> {
18        let arg = Self::to_big_float_inc(self);
19        let ret = arg.ln()?;
20        Self::from_big_float_inc(ret)
21    }
22
23    /// E to the power of `self`.
24    ///
25    /// # Errors
26    ///
27    /// ExponentOverflow - when result is too big.
28    pub fn exp(&self) -> Result<Self, Error> {
29        let arg = Self::to_big_float_inc(self);
30        let ret = arg.exp()?;
31        Self::from_big_float_inc(ret)
32    }
33
34    /// Returns logarithm of base `b` of a number.
35    ///
36    /// # Errors
37    ///
38    /// ExponentOverflow - when result is too big.
39    ///
40    /// InvalidArgument - when `self` or `b` is negative or zero.
41    ///
42    /// DivisionByZero - when `b` is equal to 1.
43    pub fn log(&self, b: &Self) -> Result<Self, Error> {
44        let arg = Self::to_big_float_inc(self);
45        let base = Self::to_big_float_inc(b);
46        let ret = arg.log(&base)?;
47        Self::from_big_float_inc(ret)
48    }
49
50    /// Returns logarithm of base 2 of a number.
51    ///
52    /// # Errors
53    ///
54    /// ExponentOverflow - when result is too big.
55    ///
56    /// InvalidArgument - when `self` or `b` is negative or zero.
57    pub fn log2(&self) -> Result<Self, Error> {
58        let mut two = Self::new();
59        two.m[DECIMAL_PARTS - 1] = DECIMAL_BASE as i16 / 5;
60        two.n = DECIMAL_POSITIONS as i16;
61        two.e = 1 - DECIMAL_POSITIONS as i8;
62        self.log(&two)
63    }
64
65    /// Returns logarithm of base 10 of a number.
66    ///
67    /// # Errors
68    ///
69    /// ExponentOverflow - when result is too big.
70    ///
71    /// InvalidArgument - when `self` or `b` is negative or zero.
72    pub fn log10(&self) -> Result<Self, Error> {
73        let mut ten = Self::new();
74        ten.m[DECIMAL_PARTS - 1] = DECIMAL_BASE as i16 / 10;
75        ten.n = DECIMAL_POSITIONS as i16;
76        ten.e = 2 - DECIMAL_POSITIONS as i8;
77        self.log(&ten)
78    }
79}
80
81#[cfg(test)]
82mod tests {
83
84    use super::*;
85    use crate::defs::DECIMAL_POSITIONS;
86    use crate::defs::DECIMAL_SIGN_NEG;
87    use crate::defs::E;
88
89    #[test]
90    fn test_log() {
91        let mut d1;
92        let mut d2;
93        let one = BigFloatNum::one();
94        let two = one.add(&one).unwrap();
95        let mut epsilon = BigFloatNum::one();
96        epsilon.e = -epsilon.n as i8 + 1 - (DECIMAL_POSITIONS as i8);
97
98        // arg = 0
99        d1 = BigFloatNum::new();
100        assert!(d1.ln().unwrap_err() == Error::InvalidArgument);
101        assert!(d1.log(&two).unwrap_err() == Error::InvalidArgument);
102
103        // base = 0
104        assert!(two.log(&d1).unwrap_err() == Error::InvalidArgument);
105
106        // arg < 0
107        d1 = BigFloatNum::one();
108        d1.sign = DECIMAL_SIGN_NEG;
109        assert!(d1.ln().unwrap_err() == Error::InvalidArgument);
110        assert!(d1.log(&two).unwrap_err() == Error::InvalidArgument);
111
112        // base < 0
113        assert!(two.log(&d1).unwrap_err() == Error::InvalidArgument);
114
115        // ln of E = 1
116        epsilon.e = -77; // 1*10^(-39)
117        assert!(E.ln().unwrap().sub(&one).unwrap().abs().cmp(&epsilon) <= 0);
118
119        // log2 of 4 = 2
120        let four = two.add(&two).unwrap();
121        assert!(
122            four.log(&two)
123                .unwrap()
124                .sub(&two)
125                .unwrap()
126                .abs()
127                .cmp(&epsilon)
128                <= 0
129        );
130
131        // log0.5 of 4 = -2
132        let half = one.div(&two).unwrap();
133        assert!(
134            four.log(&half)
135                .unwrap()
136                .add(&two)
137                .unwrap()
138                .abs()
139                .cmp(&epsilon)
140                <= 0
141        );
142
143        // base = 1
144        assert!(four.log(&one).unwrap_err() == Error::DivisionByZero);
145
146        d2 = BigFloatNum::new();
147        d2.m[0] = 4567;
148        d2.m[1] = 123;
149        d2.m[2] = 6789;
150        d2.m[3] = 2345;
151        d2.m[4] = 651;
152        d2.m[5] = 41;
153        d2.m[6] = 671;
154        d2.m[7] = 9999;
155        d2.m[8] = 0;
156        d2.m[9] = 0;
157        d2.e = -10;
158        for i in 1..1000 {
159            d2.m[2] = i;
160            d2.m[9] = i;
161            d2.n = if i < 10 {
162                1
163            } else if i < 100 {
164                2
165            } else if i < 1000 {
166                3
167            } else {
168                4
169            } + 36;
170            d2.e = -50 + (i % 100) as i8;
171            epsilon.e = -epsilon.n as i8 + 4 - (DECIMAL_POSITIONS as i8) + d2.e + d2.n as i8;
172            let ret = d2.ln().unwrap();
173            d1 = ret.exp().unwrap();
174            assert!(d2.sub(&d1).unwrap().abs().cmp(&epsilon) < 0);
175
176            // base > 1
177            let ret = d2.log(&two).unwrap();
178            d1 = two.pow(&ret).unwrap();
179            assert!(d2.sub(&d1).unwrap().abs().cmp(&epsilon) < 0);
180
181            // base < 1
182            let ret = d2.log(&half).unwrap();
183            d1 = half.pow(&ret).unwrap();
184            assert!(d2.sub(&d1).unwrap().abs().cmp(&epsilon) < 0);
185        }
186
187        // log2
188        epsilon.e = -epsilon.n as i8 + 1 - (DECIMAL_POSITIONS as i8);
189        assert!(four.log2().unwrap().sub(&two).unwrap().abs().cmp(&epsilon) <= 0);
190
191        // log10
192        d1 = BigFloatNum::new();
193        d1.m[0] = 100;
194        d1.n = 3;
195        assert!(d1.log10().unwrap().sub(&two).unwrap().abs().cmp(&epsilon) <= 0);
196    }
197}