fast_posit/underlying/
mod.rs

1//! This module contains all the implementations of the necessary underlying integer operations
2//! needed for the software implementation of posit arithmetic. These are hidden from the
3//! end-user, which only sees the sealed [`Int`] trait, implemented for `i8`, `i16`, `i32`, `i64`,
4//! and `i128`.
5
6/// The trait for the underlying machine integer types that can be used to represent a posit
7/// (only satisfied by `i8`, `i16`, `i32`, `i64`, and `i128`).
8///
9/// This is a *sealed* type.
10pub trait Int: Sealed {}
11
12/// Actual operations implemented here.
13pub trait Sealed:
14  core::fmt::Debug + core::fmt::Display + core::fmt::Binary +
15  Copy + Clone +
16  Eq + Ord +
17  core::hash::Hash + Default +
18  core::ops::Add<Self, Output=Self> + core::ops::AddAssign<Self> +
19  core::ops::Sub<Self, Output=Self> + core::ops::AddAssign<Self> +
20  // core::ops::Mul<Self, Output=Self> +
21  // core::ops::Div<Self, Output=Self> +
22  core::ops::Shl<u32, Output=Self> +
23  core::ops::Shr<u32, Output=Self> +
24  core::ops::BitAnd<Output=Self> +
25  core::ops::BitOr<Output=Self> + core::ops::BitOrAssign +
26  core::ops::BitXor<Output=Self> +
27  core::ops::Not<Output=Self> +
28  core::ops::Neg<Output=Self> +
29  From<bool> + Into<i128>
30{
31  type Unsigned: Unsigned;
32  type Double: Double<Single = Self>;
33
34  const ZERO: Self;
35  const ONE: Self;
36  const MIN: Self;
37  const MAX: Self;
38  const BITS: u32;
39
40  fn as_unsigned(self) -> Self::Unsigned;
41  fn of_unsigned(x: Self::Unsigned) -> Self;
42
43  fn as_u32(self) -> u32;
44  fn of_u32(x: u32) -> Self;
45
46  fn to_be(self) -> Self;
47  fn from_be(self) -> Self;
48
49  fn is_positive(self) -> bool;
50  fn abs(self) -> Self;
51
52  /// Logical shift right (rather than arithmetic shift). Short for `(self as uX >> n) as iX`.
53  fn lshr(self, n: u32) -> Self;
54
55  /// Set all bits more significant than `n` to 0.
56  ///
57  /// ```ignore
58  /// assert_eq!(0xabcd_i16.mask_lsb(4), 0x000d_i16)
59  /// ```
60  fn mask_lsb(self, n: u32) -> Self;
61
62  /// Set all bits less significant than `BITS - n` to 0.
63  ///
64  /// ```ignore
65  /// assert_eq!(0xabcd_i16.mask_msb(4), 0xa000_i16)
66  /// ```
67  fn mask_msb(self, n: u32) -> Self;
68
69  /// Get the lsb of `self` as a bool
70  fn get_lsb(self) -> bool;
71
72  /// Number of leading (most significant) 0 bits until the first 1.
73  fn leading_zeros(self) -> u32;
74
75  /// As [Sealed::leading_zeros], but is undefined if `self` is zero.
76  unsafe fn leading_zeros_nonzero(self) -> u32;
77
78  /// Number of leading (most significant) 0 bits until the first 1 OR number of leading 1 bits
79  /// until the first 0, *minus 1*.
80  ///
81  /// If `self` is `Int::ZERO` or `Int::MIN`, calling this function is *undefined behaviour*.
82  ///
83  /// ```ignore
84  /// # use crate::underlying::Sealed;
85  /// assert_eq!((0b00010101u8 as i8).leading_run_minus_one(), 2);
86  /// assert_eq!((0b11111000u8 as i8).leading_run_minus_one(), 4);
87  /// ```
88  unsafe fn leading_run_minus_one(self) -> u32;
89
90  /// Short for `if control < 0 { self } else { !self }`.
91  fn not_if_negative(self, control: Self) -> Self;
92
93  /// Short for `if control >= 0 { !self } else { self }`.
94  fn not_if_positive(self, control: Self) -> Self;
95
96  fn wrapping_add(self, other: Self) -> Self;
97  fn wrapping_sub(self, other: Self) -> Self;
98  fn wrapping_neg(self) -> Self;
99  fn wrapping_abs(self) -> Self;
100
101  fn overflowing_add(self, other: Self) -> (Self, bool);
102  fn carrying_add(self, other: Self, carry: bool) -> (Self, bool);
103
104  /// If `self + other` doesn't overflow, return `(self + other, false)`. If it does overflow,
105  /// return `(self.midpoint(other), true)` (i.e. `(self + other) / 2` as if it were evaluated in
106  /// a sufficiently large type).
107  fn overflowing_add_shift(self, other: Self) -> (Self, bool);
108
109  /// Multiply without overflow or loss of precision, by returning a type that's twice as wide as
110  /// `Self`.
111  fn doubling_mul(self, other: Self) -> Self::Double;
112
113  /// Compute the result of `(self << precision) / other` and `(self << precision) % other`
114  /// *without* overflow or loss of precision (by using a type that's twice as wide as `Self` for
115  /// the intermediate computation), provided that `other` is not `0` nor `-1`.
116  ///
117  /// Returns a tuple (`quotient`, `remainder`).
118  ///
119  /// # Safety
120  ///
121  /// If `other` is `Int::0` or `-Int::ONE`, in which case the quotient would be indeterminate or
122  /// overflow a `Self`, respectively, calling this function is *undefined behaviour*.
123  unsafe fn shift_div_rem(self, other: Self, precision: u32) -> (Self, Self);
124
125  /// Compute the result of a multiword left-shift. The return value is `(hi, lo, index)`, such
126  /// that, in terms of infinite precision arithmetic:
127  ///
128  /// ```ignore
129  /// self << n = (hi << Self::BITS + lo) << (8 * index)
130  /// ```
131  ///
132  /// That is, `hi, lo` are the high and low words of the shifted result, and `index` is the offset
133  /// in _bytes_, useful if we're representing the multiword number in an array.
134  fn multiword_shl(self, n: u32) -> (Self, Self, usize);  // TODO return (Self::Double, usize)
135}
136
137// TODO pub trait IntBigEndian
138
139/// This trait models the unsigned counterpart to an [`Int`].
140pub trait Unsigned:
141  core::fmt::Debug + core::fmt::Display + core::fmt::Binary +
142  Copy + Clone +
143  Eq + Ord +
144  core::ops::Shl<u32, Output=Self> +
145  core::ops::Shr<u32, Output=Self> +
146{
147  fn to_be(self) -> Self;
148
149  fn overflowing_add(self, other: Self) -> (Self, bool);
150}
151
152/// This trait models the type that is an `Int` with twice the precision (e.g. `i32::Double` =
153/// `i64`). The two ways to convert between the two are by:
154///
155///   - By multipling two `Int`s with no loss of precision, fitting into a `Double`
156///     (`doubling_mul`)
157///   - By breaking a `Double` into its hi and lo `Int`s (`components`)
158pub trait Double:
159  core::fmt::Debug +
160  Copy + Clone +
161  Eq + Ord +
162  core::ops::Shl<u32, Output=Self> +
163  core::ops::Shr<u32, Output=Self> +
164{
165  type Single: Int;
166
167  /// Break a `Double` down into its high and low `Int`s, respectively.
168  fn components_hi_lo(self) -> (Self::Single, Self::Single);
169
170  /// See [Sealed::leading_run_minus_one].
171  unsafe fn leading_run_minus_one(self) -> u32;
172}
173
174mod int;
175mod unsigned;
176mod double;
177mod const_as;
178pub use const_as::const_as;