Skip to main content

dashu_base/
bit.rs

1//! Trait definitions for bitwise operations.
2//!
3//! Most traits are only implemented for unsigned integers yet.
4
5use core::num::FpCategory;
6
7use crate::{
8    Approximation::{self, *},
9    Sign::{self, *},
10};
11
12/// Bit query for integers
13///
14/// # Examples
15///
16/// ```
17/// # use dashu_base::BitTest;
18/// // query a bit of the number
19/// assert_eq!(0b10010.bit(1), true);
20/// assert_eq!(0b10010.bit(3), false);
21/// assert_eq!(0b10010.bit(100), false);
22/// assert_eq!((-0b10010).bit(1), true);
23/// assert_eq!((-0b10010).bit(3), true);
24/// assert_eq!((-0b10010).bit(100), true);
25///
26/// // query the bit length of the number
27/// assert_eq!(0.bit_len(), 0);
28/// assert_eq!(17.bit_len(), 5);
29/// assert_eq!((-17).bit_len(), 5);
30/// assert_eq!(0b101000000.bit_len(), 9);
31/// ```
32pub trait BitTest {
33    /// Effective bit length of the binary representation.
34    ///
35    /// For 0, the length is 0.
36    ///
37    /// For positive numbers it is:
38    /// * number of digits in base 2
39    /// * the index of the top 1 bit plus one
40    /// * the floored base-2 logarithm of the number plus one.
41    ///
42    /// For negative numbers it is:
43    /// * number of digits in base 2 without the sign
44    /// * the index of the top 0 bit plus one
45    /// * the floored base-2 logarithm of the absolute value of the number plus one.
46    fn bit_len(&self) -> usize;
47
48    /// Returns true if the `n`-th bit is set in its two's complement binary representation, n starts from 0.
49    fn bit(&self, n: usize) -> bool;
50}
51
52/// Functions related to the power of two.
53///
54/// # Examples
55/// ```
56/// use dashu_base::PowerOfTwo;
57///
58/// let n = 5u32;
59/// assert!(!n.is_power_of_two());
60/// assert_eq!(n.next_power_of_two(), 8);
61/// ```
62pub trait PowerOfTwo {
63    /// Test if self is a power of two (`2^k`)
64    fn is_power_of_two(&self) -> bool;
65    /// Get the smallest power of two greater than or equal to self.
66    fn next_power_of_two(self) -> Self;
67}
68
69macro_rules! impl_bit_ops_for_uint {
70    ($($T:ty)*) => {$(
71        impl BitTest for $T {
72            #[inline]
73            fn bit_len(&self) -> usize {
74                (<$T>::BITS - self.leading_zeros()) as usize
75            }
76            #[inline]
77            fn bit(&self, position: usize) -> bool {
78                if position >= <$T>::BITS as usize {
79                    return false;
80                } else {
81                    self & (1 << position) > 0
82                }
83            }
84        }
85
86        impl PowerOfTwo for $T {
87            #[inline]
88            fn is_power_of_two(&self) -> bool {
89                <$T>::is_power_of_two(*self)
90            }
91            #[inline]
92            fn next_power_of_two(self) -> $T {
93                <$T>::next_power_of_two(self)
94            }
95        }
96    )*}
97}
98impl_bit_ops_for_uint!(u8 u16 u32 u64 u128 usize);
99
100macro_rules! impl_bit_ops_for_int {
101    ($($T:ty)*) => {$(
102        impl BitTest for $T {
103            #[inline]
104            fn bit_len(&self) -> usize {
105                self.unsigned_abs().bit_len()
106            }
107            #[inline]
108            fn bit(&self, position: usize) -> bool {
109                if position >= <$T>::BITS as usize {
110                    return self < &0;
111                } else {
112                    self & (1 << position) > 0
113                }
114            }
115        }
116    )*}
117}
118impl_bit_ops_for_int!(i8 i16 i32 i64 i128 isize);
119
120/// Support encoding and decoding of floats into (mantissa, exponent) parts.
121///
122/// See the docs of each method for the details
123///
124/// # Examples
125///
126/// ```
127/// # use dashu_base::{FloatEncoding, Approximation::*, Sign::*};
128/// use core::num::FpCategory;
129///
130/// assert_eq!(0f64.decode(), Ok((0, -1074))); // exponent will not be reduced
131/// assert_eq!(1f32.decode(), Ok((1 << 23, -23)));
132/// assert_eq!(f32::INFINITY.decode(), Err(FpCategory::Infinite));
133///
134/// assert_eq!(f64::encode(0, 1), Exact(0f64));
135/// assert_eq!(f32::encode(1, 0), Exact(1f32));
136/// assert_eq!(f32::encode(i32::MAX, 100), Inexact(f32::INFINITY, Positive));
137/// ```
138pub trait FloatEncoding {
139    /// The integer type used to represent the decoded mantissa.
140    type Mantissa;
141    /// The integer type used to represent the decoded binary exponent.
142    type Exponent;
143
144    /// Convert a float number `mantissa * 2^exponent` into `(mantissa, exponent)` parts faithfully.
145    ///
146    /// This method will not reduce the result (e.g. turn `2 * 2^-1` into `1 * 2^0`), and it
147    /// will return [Err] when the float number is nan or infinite.
148    fn decode(self) -> Result<(Self::Mantissa, Self::Exponent), FpCategory>;
149
150    /// Convert `(mantissa, exponent)` to `mantissa * 2^exponent` faithfully.
151    ///
152    /// It won't generate `NaN` values. However if the actual value is out of the
153    /// representation range, it might return an infinity or subnormal number.
154    ///
155    /// If any rounding happened during the conversion, it should follow the default
156    /// behavior defined by IEEE 754 (round to nearest, ties to even)
157    ///
158    /// The returned approximation is exact if the input can be exactly representable by f32,
159    /// otherwise the error field of the approximation contains the sign of `result - mantissa * 2^exp`.
160    fn encode(mantissa: Self::Mantissa, exponent: Self::Exponent) -> Approximation<Self, Sign>
161    where
162        Self: Sized;
163}
164
165/// Round to even floating point adjustment, based on the bottom
166/// bit of mantissa and additional 2 bits (i.e. 3 bits in units of ULP/4).
167#[inline]
168fn round_to_even_adjustment(bits: u8) -> bool {
169    bits >= 0b110 || bits == 0b011
170}
171
172impl FloatEncoding for f32 {
173    type Mantissa = i32;
174    type Exponent = i16;
175
176    #[inline]
177    fn decode(self) -> Result<(i32, i16), FpCategory> {
178        let bits: u32 = self.to_bits();
179        let sign_bit = bits >> 31;
180        let mantissa_bits = bits & 0x7fffff;
181
182        // deal with inf/nan values
183        let mut exponent = ((bits >> 23) & 0xff) as i16;
184        if exponent == 0xff {
185            return if mantissa_bits != 0 {
186                Err(FpCategory::Nan)
187            } else {
188                Err(FpCategory::Infinite)
189            };
190        }
191
192        // then parse values
193        let mantissa = if exponent == 0 {
194            // subnormal
195            exponent = -126 - 23;
196            mantissa_bits
197        } else {
198            // normal
199            exponent -= 127 + 23; // bias + mantissa shift
200            mantissa_bits | 0x800000
201        } as i32;
202
203        let sign = Sign::from(sign_bit > 0);
204        Ok((mantissa * sign, exponent))
205    }
206
207    #[inline]
208    fn encode(mantissa: i32, exponent: i16) -> Approximation<Self, Sign> {
209        if mantissa == 0 {
210            return Exact(0f32);
211        }
212
213        // clear sign
214        let sign = (mantissa < 0) as u32;
215        let mut mantissa = mantissa.unsigned_abs();
216
217        let zeros = mantissa.leading_zeros();
218        let top_bit = (u32::BITS - zeros) as i16 + exponent;
219
220        if top_bit > 128 {
221            // overflow
222            return if sign == 0 {
223                Inexact(f32::INFINITY, Sign::Positive)
224            } else {
225                Inexact(f32::NEG_INFINITY, Sign::Negative)
226            };
227        } else if top_bit < -125 - 23 {
228            // underflow
229            return if sign == 0 {
230                Inexact(0f32, Sign::Negative)
231            } else {
232                Inexact(-0f32, Sign::Positive)
233            };
234        };
235
236        let bits; // bit representation
237        let round_bits; // for rounding
238        if top_bit <= -125 {
239            // subnormal float
240            // (this branch includes 1e-125, the smallest positive normal f32)
241
242            // first remove the exponent
243            let shift = exponent + 126 + 23;
244            if shift >= 0 {
245                round_bits = 0; // not rounding is required
246                mantissa <<= shift as u32;
247            } else {
248                let shifted = mantissa << (30 + shift) as u32;
249                round_bits = (shifted >> 28 & 0b110) as u8 | ((shifted & 0xfffffff) != 0) as u8;
250                mantissa >>= (-shift) as u32;
251            }
252
253            // then compose the bit representation of f32
254            bits = (sign << 31) | mantissa;
255        } else {
256            // normal float
257            // first normalize the mantissa (and remove the top bit)
258            if mantissa == 1 {
259                mantissa = 0; // shl will overflow
260            } else {
261                mantissa <<= zeros + 1;
262            }
263
264            // then calculate the exponent (bias is 127)
265            let exponent = (exponent + 127 + u32::BITS as i16) as u32 - zeros - 1;
266
267            // then compose the bit representation of f32
268            bits = (sign << 31) | (exponent << 23) | (mantissa >> 9);
269
270            // get the low bit of mantissa and two extra bits, and adding round-to-even adjustment
271            round_bits = ((mantissa >> 7) & 0b110) as u8 | ((mantissa & 0x7f) != 0) as u8;
272        };
273
274        if round_bits & 0b11 == 0 {
275            // If two extra bits are all zeros, then the float is exact
276            Exact(f32::from_bits(bits))
277        } else {
278            let sign = Sign::from(sign > 0);
279            if round_to_even_adjustment(round_bits) {
280                // If the mantissa overflows, this correctly increases the exponent and sets the mantissa to 0.
281                // If the exponent overflows, we correctly get the representation of infinity.
282                Inexact(f32::from_bits(bits + 1), Positive * sign)
283            } else {
284                Inexact(f32::from_bits(bits), Negative * sign)
285            }
286        }
287    }
288}
289
290impl FloatEncoding for f64 {
291    type Mantissa = i64;
292    type Exponent = i16;
293
294    #[inline]
295    fn decode(self) -> Result<(i64, i16), FpCategory> {
296        let bits: u64 = self.to_bits();
297        let sign_bit = bits >> 63;
298        let mantissa_bits = bits & 0xfffffffffffff;
299
300        // deal with inf/nan values
301        let mut exponent = ((bits >> 52) & 0x7ff) as i16;
302        if exponent == 0x7ff {
303            return if mantissa_bits != 0 {
304                Err(FpCategory::Nan)
305            } else {
306                Err(FpCategory::Infinite)
307            };
308        }
309
310        // then parse values
311        let mantissa = if exponent == 0 {
312            // subnormal
313            exponent = -1022 - 52;
314            mantissa_bits
315        } else {
316            // normal
317            exponent -= 1023 + 52; // bias + mantissa shift
318            mantissa_bits | 0x10000000000000
319        } as i64;
320
321        if sign_bit == 0 {
322            Ok((mantissa, exponent))
323        } else {
324            Ok((-mantissa, exponent))
325        }
326    }
327
328    #[inline]
329    fn encode(mantissa: i64, exponent: i16) -> Approximation<Self, Sign> {
330        if mantissa == 0 {
331            return Exact(0f64);
332        }
333
334        // clear sign
335        let sign = (mantissa < 0) as u64;
336        let mut mantissa = mantissa.unsigned_abs();
337
338        let zeros = mantissa.leading_zeros();
339        let top_bit = (u64::BITS - zeros) as i16 + exponent;
340
341        if top_bit > 1024 {
342            // overflow
343            return if sign == 0 {
344                Inexact(f64::INFINITY, Sign::Positive)
345            } else {
346                Inexact(f64::NEG_INFINITY, Sign::Negative)
347            };
348        } else if top_bit < -1022 - 52 {
349            // underflow
350            return if sign == 0 {
351                Inexact(0f64, Sign::Negative)
352            } else {
353                Inexact(-0f64, Sign::Positive)
354            };
355        };
356
357        let bits; // bit representation
358        let round_bits; // for rounding
359        if top_bit <= -1022 {
360            // subnormal float
361            // (this branch includes 1e-1022, the smallest positive normal f32)
362
363            // first remove the exponent
364            let shift = exponent + 1022 + 52;
365            if shift >= 0 {
366                round_bits = 0; // not rounding is required
367                mantissa <<= shift as u32;
368            } else {
369                let shifted = mantissa << (62 + shift) as u64;
370                round_bits =
371                    (shifted >> 60 & 0b110) as u8 | ((shifted & 0xfffffffffffffff) != 0) as u8;
372                mantissa >>= (-shift) as u32;
373            }
374
375            // then compose the bit representation of f64
376            bits = (sign << 63) | mantissa;
377        } else {
378            // normal float
379            // first normalize the mantissa (and remove the top bit)
380            if mantissa == 1 {
381                mantissa = 0; // shl will overflow
382            } else {
383                mantissa <<= zeros + 1;
384            }
385
386            // then calculate the exponent (bias is 1023)
387            let exponent = (exponent + 1023 + u64::BITS as i16) as u64 - zeros as u64 - 1;
388
389            // then compose the bit representation of f64
390            bits = (sign << 63) | (exponent << 52) | (mantissa >> 12);
391
392            // get the low bit of mantissa and two extra bits, and adding round-to-even adjustment
393            round_bits = ((mantissa >> 10) & 0b110) as u8 | ((mantissa & 0x3ff) != 0) as u8;
394        };
395
396        if round_bits & 0b11 == 0 {
397            // If two extra bits are all zeros, then the float is exact
398            Exact(f64::from_bits(bits))
399        } else {
400            let sign = Sign::from(sign > 0);
401            if round_to_even_adjustment(round_bits) {
402                // If the mantissa overflows, this correctly increases the exponent and sets the mantissa to 0.
403                // If the exponent overflows, we correctly get the representation of infinity.
404                Inexact(f64::from_bits(bits + 1), Positive * sign)
405            } else {
406                Inexact(f64::from_bits(bits), Negative * sign)
407            }
408        }
409    }
410}
411
412#[cfg(test)]
413mod tests {
414    use super::*;
415
416    #[test]
417    fn test_float_encoding() {
418        // special values
419        assert_eq!(f32::INFINITY.decode(), Err(FpCategory::Infinite));
420        assert_eq!(f32::NEG_INFINITY.decode(), Err(FpCategory::Infinite));
421        assert_eq!(f32::NAN.decode(), Err(FpCategory::Nan));
422        assert_eq!(f64::INFINITY.decode(), Err(FpCategory::Infinite));
423        assert_eq!(f64::NEG_INFINITY.decode(), Err(FpCategory::Infinite));
424        assert_eq!(f64::NAN.decode(), Err(FpCategory::Nan));
425
426        // round trip test
427        let f32_cases = [
428            0.,
429            -1.,
430            1.,
431            f32::MIN,
432            f32::MAX,
433            f32::MIN_POSITIVE,
434            -f32::MIN_POSITIVE,
435            f32::EPSILON,
436            f32::from_bits(0x1),      // smallest f32
437            f32::from_bits(0x7ff),    // some subnormal value
438            f32::from_bits(0x7fffff), // largest subnormal number
439            f32::from_bits(0x800000), // smallest normal number
440            -123.4567,
441            core::f32::consts::PI,
442        ];
443        for f in f32_cases {
444            let (man, exp) = f.decode().unwrap();
445            assert_eq!(f32::encode(man, exp), Exact(f));
446        }
447
448        let f64_cases = [
449            0.,
450            -1.,
451            1.,
452            f64::MIN,
453            f64::MAX,
454            f64::MIN_POSITIVE,
455            -f64::MIN_POSITIVE,
456            f64::EPSILON,
457            f64::from_bits(0x1),              // smallest f64
458            f64::from_bits(0x7fffff),         // largest subnormal number
459            f64::from_bits(0xfffffffffffff),  // some subnormal value
460            f64::from_bits(0x10000000000000), // smallest normal number
461            -123456.789012345,
462            core::f64::consts::PI,
463        ];
464        for f in f64_cases {
465            let (man, exp) = f.decode().unwrap();
466            assert_eq!(f64::encode(man, exp), Exact(f));
467        }
468
469        // test out of ranges
470        assert_eq!(f32::encode(1, 128), Inexact(f32::INFINITY, Sign::Positive));
471        assert_eq!(f32::encode(-1, 128), Inexact(f32::NEG_INFINITY, Sign::Negative));
472        assert_eq!(f32::encode(1, -150), Inexact(0f32, Sign::Negative));
473        assert_eq!(f32::encode(-1, -150), Inexact(-0f32, Sign::Positive));
474        assert_eq!(f64::encode(1, 1024), Inexact(f64::INFINITY, Sign::Positive));
475        assert_eq!(f64::encode(-1, 1024), Inexact(f64::NEG_INFINITY, Sign::Negative));
476        assert_eq!(f64::encode(1, -1075), Inexact(0f64, Sign::Negative));
477        assert_eq!(f64::encode(-1, -1075), Inexact(-0f64, Sign::Positive));
478
479        // test rounding
480        assert_eq!(f32::encode(3, -150), Inexact(f32::from_bits(0x00000002), Sign::Positive));
481        assert_eq!(f32::encode(-5, -150), Inexact(f32::from_bits(0x80000002), Sign::Positive));
482        assert_eq!(f32::encode(i32::MAX, 50), Inexact(f32::from_bits(0x68000000), Sign::Positive));
483        assert_eq!(
484            f32::encode(i32::MAX, -150),
485            Inexact(f32::from_bits(0x04000000), Sign::Positive)
486        );
487        assert_eq!(
488            f32::encode(i32::MAX, -160),
489            Inexact(f32::from_bits(0x00100000), Sign::Positive)
490        );
491        assert_eq!(
492            f32::encode(i32::MAX, -170),
493            Inexact(f32::from_bits(0x00000400), Sign::Positive)
494        );
495        assert_eq!(
496            f64::encode(3, -1075),
497            Inexact(f64::from_bits(0x0000000000000002), Sign::Positive)
498        );
499        assert_eq!(
500            f64::encode(-5, -1075),
501            Inexact(f64::from_bits(0x8000000000000002), Sign::Positive)
502        );
503        assert_eq!(
504            f64::encode(i64::MAX, 500),
505            Inexact(f64::from_bits(0x6320000000000000), Sign::Positive)
506        );
507        assert_eq!(
508            f64::encode(i64::MAX, -1075),
509            Inexact(f64::from_bits(0x00b0000000000000), Sign::Positive)
510        );
511        assert_eq!(
512            f64::encode(i64::MAX, -1095),
513            Inexact(f64::from_bits(0x0000040000000000), Sign::Positive)
514        );
515        assert_eq!(f64::encode(i64::MAX, -1115), Inexact(f64::from_bits(0x400000), Sign::Positive));
516
517        // other cases
518        assert_eq!(f32::encode(1, 0), Exact(1f32));
519        assert_eq!(f64::encode(1, 0), Exact(1f64));
520        assert_eq!(f32::encode(0x1000000, -173), Exact(f32::from_bits(0x1)));
521        assert_eq!(f64::encode(0x40000000000000, -1128), Exact(f64::from_bits(0x1)));
522    }
523}