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