num_bigfloat/
defs.rs

1//!  Definitions.
2
3#[cfg(feature = "serde")]
4use serde::{Deserialize, Serialize};
5
6/// Number of "digits" in BigFloat number.
7pub const DECIMAL_PARTS: usize = 10;
8
9/// i64::MAX.
10pub const I64_MAX: BigFloatNum = BigFloatNum {
11    m: [0, 0, 0, 0, 0, 8070, 4775, 3685, 3720, 9223],
12    n: DECIMAL_POSITIONS as i16,
13    sign: DECIMAL_SIGN_POS,
14    e: -(DECIMAL_POSITIONS as i8 - 19),
15};
16
17/// i64::MIN.
18pub const I64_MIN: BigFloatNum = BigFloatNum {
19    m: [0, 0, 0, 0, 0, 8080, 4775, 3685, 3720, 9223],
20    n: DECIMAL_POSITIONS as i16,
21    sign: DECIMAL_SIGN_NEG,
22    e: -(DECIMAL_POSITIONS as i8 - 19),
23};
24
25/// u64::MAX.
26pub const U64_MAX: BigFloatNum = BigFloatNum {
27    m: [0, 0, 0, 0, 0, 1615, 955, 737, 6744, 1844],
28    n: DECIMAL_POSITIONS as i16,
29    sign: DECIMAL_SIGN_POS,
30    e: -(DECIMAL_POSITIONS as i8 - 20),
31};
32
33// i128::MAX
34pub const I128_MAX: BigFloatNum = BigFloatNum {
35    m: [7270, 4105, 1588, 3037, 1687, 3173, 4692, 3460, 4118, 1701],
36    n: DECIMAL_POSITIONS as i16,
37    sign: DECIMAL_SIGN_POS,
38    e: -1,
39};
40
41/// i128::MIN.
42pub const I128_MIN: BigFloatNum = BigFloatNum {
43    m: [7280, 4105, 1588, 3037, 1687, 3173, 4692, 3460, 4118, 1701],
44    n: DECIMAL_POSITIONS as i16,
45    sign: DECIMAL_SIGN_NEG,
46    e: -1,
47};
48
49/// u128::MAX.
50pub const U128_MAX: BigFloatNum = BigFloatNum {
51    m: [4550, 8211, 3176, 6074, 3374, 6346, 9384, 6920, 8236, 3402],
52    n: DECIMAL_POSITIONS as i16,
53    sign: DECIMAL_SIGN_POS,
54    e: -1,
55};
56
57/// Number representation.
58#[derive(Copy, Clone, Debug)]
59#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
60pub struct BigFloatNum {
61    pub(crate) sign: i8,                // sign
62    pub(crate) e: i8,                   // exponent
63    pub(crate) n: i16, // the number of decimal positions in the mantissa excluding leading zeroes
64    pub(crate) m: [i16; DECIMAL_PARTS], // mantissa
65}
66
67/// Possible errors.
68#[derive(Eq, PartialEq, Debug, Copy, Clone)]
69pub enum Error {
70    /// Exponent value becomes greater than the upper bound.
71    /// Error stores sign of resulting number.
72    ExponentOverflow(i8),
73
74    /// Divizor is zero.
75    DivisionByZero,
76
77    /// Argument must not be a negative number.
78    ArgumentIsNegative,
79
80    /// Invalid argument.
81    InvalidArgument,
82}
83
84/// Rounding modes.
85#[derive(Eq, PartialEq, Debug, Copy, Clone)]
86pub enum RoundingMode {
87    /// Round half toward positive infinity.
88    Up,
89
90    /// Round half toward negative infinity.
91    Down,
92
93    /// Round half toward zero.
94    ToZero,
95
96    /// Round half away from zero.
97    FromZero,
98
99    /// Round half to even.
100    ToEven,
101
102    /// Round half to odd.
103    ToOdd,
104}
105
106pub const DECIMAL_BASE_LOG10: usize = 4; // number decimal positions in a digit = log10(DECIMAL_BASE)
107pub const DECIMAL_POSITIONS: usize = DECIMAL_PARTS * DECIMAL_BASE_LOG10;
108pub const DECIMAL_BASE: usize = 10000; // 9999 is the maximum of a digit
109pub const DECIMAL_SIGN_POS: i8 = 1; // + sign
110pub const DECIMAL_SIGN_NEG: i8 = -1; // - sign
111pub const DECIMAL_MIN_EXPONENT: i8 = -128; // min exponent value
112pub const DECIMAL_MAX_EXPONENT: i8 = 127; // max exponent value
113pub const ZEROED_MANTISSA: [i16; DECIMAL_PARTS] = [0; DECIMAL_PARTS];
114
115/// Zero.
116pub const ZERO: BigFloatNum = BigFloatNum {
117    m: ZEROED_MANTISSA,
118    n: 0,
119    sign: DECIMAL_SIGN_POS,
120    e: 0,
121};
122
123/// One.
124pub const ONE: BigFloatNum = BigFloatNum {
125    m: [0, 0, 0, 0, 0, 0, 0, 0, 0, 1000],
126    n: DECIMAL_POSITIONS as i16,
127    sign: DECIMAL_SIGN_POS,
128    e: 1 - (DECIMAL_POSITIONS as i8),
129};
130
131/// Two.
132pub const TWO: BigFloatNum = BigFloatNum {
133    m: [0, 0, 0, 0, 0, 0, 0, 0, 0, 2000],
134    n: DECIMAL_POSITIONS as i16,
135    sign: DECIMAL_SIGN_POS,
136    e: 1 - (DECIMAL_POSITIONS as i8),
137};
138
139/// Eulers number.
140pub const E: BigFloatNum = BigFloatNum {
141    m: [7757, 6249, 3526, 7471, 6028, 2353, 9045, 2845, 2818, 2718],
142    n: DECIMAL_POSITIONS as i16,
143    sign: DECIMAL_SIGN_POS,
144    e: 1 - (DECIMAL_POSITIONS as i8),
145};
146
147/// Pi number.
148pub const PI: BigFloatNum = BigFloatNum {
149    m: [4197, 288, 2795, 3383, 6264, 2384, 9793, 5358, 5926, 3141],
150    n: DECIMAL_POSITIONS as i16,
151    sign: DECIMAL_SIGN_POS,
152    e: 1 - (DECIMAL_POSITIONS as i8),
153};
154
155/// Largest value possible.
156pub const MAX: BigFloatNum = BigFloatNum {
157    m: [9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999],
158    n: DECIMAL_POSITIONS as i16,
159    sign: DECIMAL_SIGN_POS,
160    e: DECIMAL_MAX_EXPONENT,
161};
162
163/// Smalles value possible.
164pub const MIN: BigFloatNum = BigFloatNum {
165    m: [9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999],
166    n: DECIMAL_POSITIONS as i16,
167    sign: DECIMAL_SIGN_NEG,
168    e: DECIMAL_MAX_EXPONENT,
169};
170
171/// Smalles positive number.
172pub const MIN_POSITIVE: BigFloatNum = BigFloatNum {
173    m: [1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
174    n: 1,
175    sign: DECIMAL_SIGN_POS,
176    e: DECIMAL_MIN_EXPONENT,
177};
178
179/// Smalles positive normal number.
180pub const MIN_POSITIVE_NORMAL: BigFloatNum = BigFloatNum {
181    m: [0, 0, 0, 0, 0, 0, 0, 0, 0, 1000],
182    n: 1,
183    sign: DECIMAL_SIGN_POS,
184    e: DECIMAL_MIN_EXPONENT,
185};
186
187/// Creation and number manipulation functions.
188impl BigFloatNum {
189    /// Return new BigFloat with value zero.
190    pub fn new() -> Self {
191        BigFloatNum {
192            sign: DECIMAL_SIGN_POS,
193            e: 0,
194            n: 0,
195            m: ZEROED_MANTISSA,
196        }
197    }
198
199    /// Return BigFloat with the value of 1.
200    pub fn one() -> Self {
201        let mut val = Self::new();
202        val.m[DECIMAL_PARTS - 1] = DECIMAL_BASE as i16 / 10;
203        val.n = DECIMAL_POSITIONS as i16;
204        val.e = 1 - DECIMAL_POSITIONS as i8;
205        val
206    }
207
208    /// Create a BigFloat value from a sequence of `bytes`. Each byte must represent a decimal digit.
209    /// First byte is the most significant. The length of `bytes` can be any. If the length of
210    /// `bytes` is greater than required, then the remaining part is ignored.
211    /// If `sign` is negative, then the resulting BigFloat will be
212    /// negative.
213    pub fn from_bytes(bytes: &[u8], sign: i8, exponent: i8) -> BigFloatNum {
214        let mut mantissa = ZEROED_MANTISSA;
215        let mut n: usize = 0;
216        let mut p: i16 = 1;
217        let d = if bytes.len() > DECIMAL_POSITIONS { DECIMAL_POSITIONS } else { bytes.len() };
218        for i in 1..d + 1 {
219            mantissa[n] += (bytes[d - i] % 10) as i16 * p;
220            p *= 10;
221            if p == DECIMAL_BASE as i16 {
222                n += 1;
223                p = 1;
224            }
225        }
226
227        BigFloatNum {
228            sign: if sign >= 0 { DECIMAL_SIGN_POS } else { DECIMAL_SIGN_NEG },
229            e: exponent,
230            n: Self::num_digits(&mantissa),
231            m: mantissa,
232        }
233    }
234
235    /// Get BigFloat's mantissa as bytes. Each byte represents a decimal digit.
236    /// First byte is the most significant. The length of `bytes` can be any. If the length of
237    /// `bytes` is smaller than required, then remaining part of mantissa will be omitted.
238    ///
239    /// The length of mantissa can be determined using `get_mantissa_len`.
240    pub fn get_mantissa_bytes(&self, bytes: &mut [u8]) {
241        let mut n: usize = 0;
242        let mut p: i16 = 1;
243        let d = if bytes.len() < self.n as usize { bytes.len() } else { self.n as usize };
244        for i in 1..d + 1 {
245            bytes[d - i] = ((self.m[n] / p) % 10) as u8;
246            p *= 10;
247            if p == DECIMAL_BASE as i16 {
248                n += 1;
249                p = 1;
250            }
251        }
252    }
253
254    /// Return the number of decimal positions filled in the mantissa.
255    pub fn get_mantissa_len(&self) -> usize {
256        self.n as usize
257    }
258
259    /// Return true if the number is zero.
260    pub fn is_zero(&self) -> bool {
261        self.n == 0
262    }
263
264    /// Return true if integer part of number is zero.
265    pub fn is_int_even(&self) -> bool {
266        let int = self.int();
267        if int.e < 0 {
268            let p = int.n + int.e as i16;
269            let mut d = int.m[p as usize / DECIMAL_BASE_LOG10];
270            let mut i = p % DECIMAL_BASE_LOG10 as i16;
271            while i > 0 {
272                d /= 10;
273                i -= 1;
274            }
275            d & 1 == 0
276        } else if int.e == 0 {
277            int.m[0] & 1 == 0
278        } else {
279            true
280        }
281    }
282
283    /// Returns true if `self` is subnormal.
284    pub fn is_subnormal(&self) -> bool {
285        self.n < DECIMAL_POSITIONS as i16 && self.e == DECIMAL_MIN_EXPONENT
286    }
287}