fast_posit/posit/quire/basics.rs
1use super::*;
2
3impl<
4 const N: u32,
5 const ES: u32,
6 const SIZE: usize,
7> Quire<N, ES, SIZE> {
8 /// The quire size in bits.
9 ///
10 /// # Example
11 ///
12 /// ```
13 /// # use fast_posit::*;
14 /// assert_eq!(q16::BITS, 256);
15 /// ```
16 pub const BITS: u32 = Self::SIZE as u32 * 8;
17
18 /// The quire size in bytes (i.e. parameter `SIZE`).
19 ///
20 /// # Example
21 ///
22 /// ```
23 /// # use fast_posit::*;
24 /// assert_eq!(q16::SIZE, 32);
25 /// ```
26 pub const SIZE: usize = {
27 assert!(SIZE >= Self::MIN_SIZE, "This quire type has fewer than the minimum number of bytes");
28 // if const { SIZE < Self::MIN_SIZE } { compile_error!("asdf") }
29 SIZE
30 };
31
32 /// Construct a quire from its raw bit representation, as a byte array in little-endian order.
33 ///
34 /// # Example
35 ///
36 /// ```
37 /// # use fast_posit::*;
38 /// let quire = q8::from_le_bytes([0,0,0,0,0,0, 1,0,0,0,0,0, 0,0,0,0]);
39 /// assert_eq!(p8::round_from(&quire), p8::ONE);
40 /// ```
41 #[inline]
42 pub const fn from_le_bytes(bytes: [u8; SIZE]) -> Self {
43 Self(bytes)
44 }
45
46 /// Construct a quire from its raw bit representation, as a byte array in big-endian order.
47 ///
48 /// # Example
49 ///
50 /// ```
51 /// # use fast_posit::*;
52 /// let quire = q8::from_be_bytes([0,0,0,0, 0,0,0,0,0,1, 0,0,0,0,0,0]);
53 /// assert_eq!(p8::round_from(&quire), p8::ONE);
54 /// ```
55 #[inline]
56 pub const fn from_be_bytes(mut bytes: [u8; SIZE]) -> Self {
57 bytes.as_mut_slice().reverse();
58 Self::from_le_bytes(bytes)
59 }
60
61 /// Return the raw bit representation of a quire, as a byte array in little-endian order.
62 ///
63 /// # Example
64 ///
65 /// ```
66 /// # use fast_posit::*;
67 /// let bytes = q8::NAR.to_le_bytes();
68 /// assert_eq!(bytes, [0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,0x80]);
69 /// ```
70 #[inline]
71 pub const fn to_le_bytes(self) -> [u8; SIZE] {
72 self.0
73 }
74
75 /// The quire size in u64s (= [`BITS`](Self::BITS) / 64).
76 pub(crate) const LEN_U64: usize = Self::BITS as usize / 64;
77
78 /// Access the storage as an array of `u64`s, in little endian order.
79 ///
80 /// Limitation: even though the return size is known, we cannot return an `&[u64; N]` due to
81 /// limitations in the Rust type system. We have to hope that the compiler will inline and fold
82 /// the slice len :)
83 #[inline(always)]
84 pub(crate) const fn as_u64_array(&self) -> &[u64] {
85 const { assert!(SIZE.is_multiple_of(8), "Quire SIZE must be a multiple of 64 bits (8 bytes)"); }
86 const { assert!(cfg!(target_endian = "little"), "Big-endian targets are not currently supported") }
87 let ptr = self.0.as_ptr() as *const u64;
88 // SAFETY: ptr and len form a valid slice; the size and alignment is correct, and any bit
89 // pattern is a valid u64 value.
90 unsafe { core::slice::from_raw_parts(ptr, Self::LEN_U64) }
91 }
92
93 #[inline(always)]
94 pub(crate) const fn as_u64_array_mut(&mut self) -> &mut [u64] {
95 const { assert!(SIZE.is_multiple_of(8), "Quire SIZE must be a multiple of 64 bits (8 bytes)"); }
96 const { assert!(cfg!(target_endian = "little"), "Big-endian targets are not currently supported") }
97 let ptr = self.0.as_mut_ptr() as *mut u64;
98 // SAFETY: ptr and len form a valid slice; the size and alignment is correct, and any bit
99 // pattern is a valid u64 value.
100 unsafe { core::slice::from_raw_parts_mut(ptr, Self::LEN_U64) }
101 }
102
103 #[inline(always)]
104 pub(crate) const fn as_int_array<Int: crate::Int>(&self) -> &[Int] {
105 const { assert!(Self::BITS % Int::BITS == 0, "Quire BITS must be a multiple of Int bits"); }
106 const { assert!(cfg!(target_endian = "little"), "Big-endian targets are not currently supported") }
107 let ptr = self.0.as_ptr() as *const Int;
108 // SAFETY: ptr and len form a valid slice; the size and alignment is correct, and any bit
109 // pattern is a valid Int value.
110 unsafe { core::slice::from_raw_parts(ptr, Self::BITS as usize / Int::BITS as usize) }
111 }
112
113 /// Auxiliary const: the maximum (positive) exponent of a `Posit<N, ES, Int>`. The size of the
114 /// quire is directly related to this (see [`Self::MIN_SIZE`] and [`Self::WIDTH`] below).
115 pub(crate) const MAX_EXP: u32 = {
116 assert!(ES < 20, "Cannot use the quire with very high ES (≥ 20)");
117 let max_exp = Posit::<N, ES, i128>::MAX_EXP;
118 if 0 <= max_exp && max_exp < 1 << 31 {
119 max_exp as u32
120 } else {
121 unreachable!()
122 }
123 };
124
125 /// The minimum [`SIZE`](Self::SIZE) of a quire for [`Posit<N, ES, Int>`], in bytes.
126 ///
127 /// # Example
128 ///
129 /// ```
130 /// # use fast_posit::*;
131 /// assert_eq!(q16::MIN_SIZE, 29);
132 /// ```
133 pub const MIN_SIZE: usize = {
134 // At worst, need to be able to represent [Posit::MAX]² + [Posit::MIN]² as a fixed point
135 // number. So that's a number of bits equal to 2×2×max_exp. Then add 1 sign bit: that's the
136 // minimum quire size in bits.
137 let min_size_bits = 4 * Self::MAX_EXP + 1;
138 min_size_bits.div_ceil(8) as usize
139 };
140
141 /// The minimum number of operations on the quire that can lead to overflow is
142 /// 2 <sup>[`PROD_LIMIT`](Self::PROD_LIMIT)</sup>; any number of [`Self::add_prod`] calls
143 /// smaller than that is *guaranteed* not to overflow.
144 ///
145 /// # Example
146 ///
147 /// ```
148 /// # use fast_posit::*;
149 /// assert_eq!(q32::PROD_LIMIT, 31); // Can do at least 2^31 - 1 products without overflow
150 /// ```
151 pub const PROD_LIMIT: u32 = {
152 // The biggest possible product (Posit::MAX * Posit::MAX) takes `4 * MAX_EXP` bits. It can be
153 // accumulated `2 ^ M` times, where `M` is the difference between that and this quire's
154 // `SIZE`, before it overflows.
155 let min_size_bits = 4 * Self::MAX_EXP + 1;
156 Self::BITS - min_size_bits
157 };
158
159 /// The minimum number of additions of posits that can lead to overflow is
160 /// 2 <sup>[`SUM_LIMIT`](Self::SUM_LIMIT)</sup>; any number of `+=` or `-=` operations smaller
161 /// than that is *guaranteed* not to overflow.
162 ///
163 /// # Example
164 ///
165 /// ```
166 /// # use fast_posit::*;
167 /// assert_eq!(q32::SUM_LIMIT, 151); // Can sum at least 2^151 - 1 terms without overflow
168 /// ```
169 pub const SUM_LIMIT: u32 = {
170 // The biggest possible posit value (Posit::MAX) takes `3 * MAX_EXP` bits. It can be
171 // accumulated `2 ^ M` times, where `M` is the difference between that and this quire's
172 // `SIZE`, before it overflows.
173 let min_size_bits = 3 * Self::MAX_EXP + 1;
174 Self::BITS - min_size_bits
175 };
176
177 /// The position of the fixed point, that is: "1.0" is represented in the quire as `1 << WIDTH`.
178 pub(crate) const WIDTH: u32 = {
179 let _ = Self::SIZE;
180 2 * Self::MAX_EXP
181 };
182
183 // TODO assert this on operations with posits (cannot assert here because needs to take into
184 // account the posit's underlying Int):
185 // assert!(SIZE % N == 0, "The size of the quire type is not a multiple of the posit size");
186
187 /// The quire that represents the posit number [0](Posit::ZERO).
188 pub const ZERO: Self = Self([0; SIZE]);
189
190 /// The quire that represents the posit value [`NaR`](Posit::NAR).
191 pub const NAR: Self = {
192 let mut nar = Self::ZERO;
193 nar.0[Self::SIZE - 1] = i8::MIN as u8;
194 nar
195 };
196
197 /// The quire with the greatest value, equal to `-Self::MIN`.
198 ///
199 /// Any sum of a positive value (be it posit, product of posits, or quire) onto
200 /// [`MAX`](Self::MAX) will result in overflow, making the result [`NaR`][Self::NAR].
201 ///
202 /// # Example
203 ///
204 /// ```
205 /// # use fast_posit::*;
206 /// let mut quire = q32::MAX;
207 /// quire += p32::MIN_POSITIVE;
208 /// assert!(quire.is_nar())
209 /// ```
210 pub const MAX: Self = {
211 let mut bytes_le = [0xff; SIZE];
212 bytes_le[SIZE - 1] = 0x7f;
213 Self::from_le_bytes(bytes_le)
214 };
215
216 /// The quire with the smallest value, equal to `-Self::MAX`.
217 ///
218 /// Any sum of a negative value (be it posit, product of posits, or quire) onto
219 /// [`MIN`](Self::MIN) will result in overflow, making the result [`NaR`][Self::NAR].
220 ///
221 /// # Example
222 ///
223 /// ```
224 /// # use fast_posit::*;
225 /// let mut quire = q32::MIN;
226 /// quire -= p32::MIN_POSITIVE;
227 /// assert!(quire.is_nar())
228 /// ```
229 pub const MIN: Self = {
230 let mut bytes_le = [0x00; SIZE];
231 bytes_le[SIZE - 1] = 0x80;
232 bytes_le[0] |= 0x01;
233 Self::from_le_bytes(bytes_le)
234 };
235
236 /// Checks whether `self` represents a NaR value.
237 ///
238 /// # Example
239 ///
240 /// ```
241 /// # use fast_posit::*;
242 /// assert!(q32::NAR.is_nar());
243 /// ```
244 pub const fn is_nar(&self) -> bool {
245 let _ = Self::NAR;
246 // This is more optimised than it looks. If the quire is not NaR, which is the "normal" and
247 // thus more important case to optimise, then most likely it will either start with
248 // `0b00…001…` (positive) of `0b11…110…` (negative), and thus return right away on the first
249 // if statement. This is because the only way it starts with `0b1000…` and yet is not NaR is
250 // if it's very very close to overflowing on the negative side; this is *exceedingly*
251 // unlikely.
252 //
253 // Therefore, for almost all cases where the quire is not NaR, we only need a compare and
254 // branch. Only on when the quire is NaR, or in the rare cases where it's not NaR but still
255 // starts with `0b1000…`, will we need to scan through the whole thing.
256 let quire: &[u64] = self.as_u64_array();
257 if crate::utl::likely(quire[quire.len() - 1] != i64::MIN as u64) {
258 false
259 } else {
260 self.is_nar_slow()
261 }
262 }
263
264 // #[cold]
265 // #[inline(never)]
266 const fn is_nar_slow(&self) -> bool {
267 // Written in this awkward way because it's a `const fn`...
268 let quire: &[u64] = self.as_u64_array();
269 let mut i = 0;
270 let mut acc = 0;
271 while i < quire.len() - 1 {
272 acc |= quire[i];
273 i += 1
274 }
275 acc == 0
276 }
277
278 /// Equivalent to `*self = Self::NAR`, but on a cold branch to ensure it does NOT get inlined and
279 /// pollute the i-cache.
280 #[cold]
281 #[inline(never)]
282 pub(crate) fn set_nar(&mut self) {
283 let q = self.as_u64_array_mut();
284 let n = q.len();
285 for i in &mut q[..n-1] {
286 *i = 0;
287 }
288 q[n - 1] = i64::MIN as u64
289 }
290}
291
292#[cfg(test)]
293mod tests {
294 use super::*;
295
296 /// Source: <https://posithub.org/docs/posit_standard-2.pdf#subsection.3.2>
297 #[test]
298 fn bits() {
299 assert_eq!(crate::q8::BITS, 128);
300 assert_eq!(crate::q16::BITS, 256);
301 assert_eq!(crate::q32::BITS, 512);
302 assert_eq!(crate::q64::BITS, 1024);
303 }
304
305 /// Source: <https://posithub.org/docs/posit_standard-2.pdf#subsection.3.2>
306 #[test]
307 fn size() {
308 assert_eq!(crate::q8::SIZE, 16);
309 assert_eq!(crate::q16::SIZE, 32);
310 assert_eq!(crate::q32::SIZE, 64);
311 assert_eq!(crate::q64::SIZE, 128);
312 }
313
314 /// Source: <https://posithub.org/docs/posit_standard-2.pdf#subsection.3.4>
315 #[test]
316 fn width() {
317 assert_eq!(crate::q8::WIDTH, 8 * 8 - 16);
318 assert_eq!(crate::q16::WIDTH, 8 * 16 - 16);
319 assert_eq!(crate::q32::WIDTH, 8 * 32 - 16);
320 assert_eq!(crate::q64::WIDTH, 8 * 64 - 16);
321 }
322
323 /// Source: <https://posithub.org/docs/posit_standard-2.pdf#subsection.3.2>
324 #[test]
325 fn min_size() {
326 assert_eq!(8 * crate::q8::MIN_SIZE, 96 + 8);
327 assert_eq!(8 * crate::q16::MIN_SIZE, 224 + 8);
328 assert_eq!(8 * crate::q32::MIN_SIZE, 480 + 8);
329 assert_eq!(8 * crate::q64::MIN_SIZE, 992 + 8);
330 }
331
332 /// With the above `MIN_SIZE`s, still compiles fine, but below that it doesn't (see
333 /// [tests_compile_fail]).
334 #[test]
335 fn min_size_compiles() {
336 let _ = Quire::<8, 2, {96 /8 + 1}>::SIZE;
337 let _ = Quire::<16, 2, {224/8 + 1}>::SIZE;
338 let _ = Quire::<32, 2, {480/8 + 1}>::SIZE;
339 let _ = Quire::<64, 2, {992/8 + 1}>::SIZE;
340 }
341
342 /// Source: <https://posithub.org/docs/posit_standard-2.pdf#subsection.3.2>
343 #[test]
344 fn sum_limit() {
345 assert_eq!(crate::q8::SUM_LIMIT, 55);
346 assert_eq!(crate::q16::SUM_LIMIT, 87);
347 assert_eq!(crate::q32::SUM_LIMIT, 151);
348 assert_eq!(crate::q64::SUM_LIMIT, 279);
349 }
350
351 /// Source: <https://posithub.org/docs/posit_standard-2.pdf#subsection.3.2>
352 #[test]
353 fn prod_limit() {
354 assert_eq!(crate::q8::PROD_LIMIT, 31);
355 assert_eq!(crate::q16::PROD_LIMIT, 31);
356 assert_eq!(crate::q32::PROD_LIMIT, 31);
357 assert_eq!(crate::q64::PROD_LIMIT, 31);
358 }
359
360 #[test]
361 fn is_nar() {
362 assert!(crate::q8::NAR.is_nar());
363 assert!(crate::q16::NAR.is_nar());
364 assert!(crate::q32::NAR.is_nar());
365 assert!(crate::q64::NAR.is_nar());
366 }
367
368 #[test]
369 fn is_nar_manual() {
370 let bits = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80];
371 assert!(crate::q8::from_le_bytes(bits).is_nar());
372 let bits = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x81];
373 assert!(!crate::q8::from_le_bytes(bits).is_nar());
374 let bits = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x42, 0, 0x80];
375 assert!(!crate::q8::from_le_bytes(bits).is_nar());
376 let bits = [0, 0, 0, 0x42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80];
377 assert!(!crate::q8::from_le_bytes(bits).is_nar());
378 let bits = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f];
379 assert!(!crate::q8::from_le_bytes(bits).is_nar());
380 let bits = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
381 assert!(!crate::q8::from_le_bytes(bits).is_nar());
382 }
383
384 #[test]
385 fn set_nar() {
386 let mut q = crate::q8::from_le_bytes([0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf]);
387 assert!(!q.is_nar());
388 q.set_nar();
389 assert!(q.is_nar());
390 }
391}
392
393mod tests_compile_fail {
394 // TODO fix sizes in the future when relaxing the "multiple of 64 bits" constraint
395
396 /// ```compile_fail
397 /// use fast_posit::Quire;
398 /// let mut q: Quire<8, 2, /*12*/ 8> = Quire::ZERO;
399 /// q += fast_posit::p8::ONE;
400 /// ```
401 #[allow(dead_code)]
402 fn quire_size_too_small_8() {}
403
404 /// ```compile_fail
405 /// use fast_posit::Quire;
406 /// let mut q: Quire<16, 2, /*28*/ 24> = Quire::ZERO;
407 /// q += fast_posit::p16::ONE;
408 /// ```
409 #[allow(dead_code)]
410 fn quire_size_too_small_16() {}
411
412 /// ```compile_fail
413 /// use fast_posit::Quire;
414 /// let mut q: Quire<32, 2, /*60*/ 56> = Quire::ZERO;
415 /// q += fast_posit::p32::ONE;
416 /// ```
417 #[allow(dead_code)]
418 fn quire_size_too_small_32() {}
419
420 /// ```compile_fail
421 /// use fast_posit::Quire;
422 /// let mut q: Quire<64, 2, /*124*/ 120> = Quire::ZERO;
423 /// q += fast_posit::p64::ONE;
424 /// ```
425 #[allow(dead_code)]
426 fn quire_size_too_small_64() {}
427}