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;