1use super::*;
2use crate::RoundFrom;
3
4impl<
5 const N: u32,
6 const ES: u32,
7 const SIZE: usize,
8> Quire<N, ES, SIZE> {
9 fn leading_run(&self) -> u32 {
11 let quire: &[u64] = self.as_u64_array();
12 let idx_last = quire.len() - 1;
13 match quire[idx_last] as i64 >= 0 {
14 true => {
15 for i in 0 .. quire.len() {
16 if quire[idx_last - i] != 0 {
17 return i as u32 * 64 + quire[idx_last - i].leading_zeros()
18 }
19 }
20 quire.len() as u32 * 64
21 },
22 false => {
23 for i in 0 .. quire.len() {
24 if quire[idx_last - i] != u64::MAX {
25 return i as u32 * 64 + quire[idx_last - i].leading_ones()
26 }
27 }
28 quire.len() as u32 * 64
29 },
30 }
31 }
32}
33
34impl<
35 const N: u32,
36 const ES: u32,
37 Int: crate::Int,
38 const SIZE: usize,
39> RoundFrom<&'_ Quire<N, ES, SIZE>> for Posit<N, ES, Int> {
40 fn round_from(value: &'_ Quire<N, ES, SIZE>) -> Self {
56 const { assert!(Int::BITS <= 64, "Only posits up to 64 bits are currently supported") };
57
58 if value.is_nar() { return Posit::NAR }
60 let leading = value.leading_run() - 1;
63
64 if leading + 1 == Quire::<N, ES, SIZE>::BITS {
67 return unsafe { core::mem::transmute_copy(value) }
69 }
70
71 let leading_ints = (leading / Int::BITS) as usize;
84 let leading_bits = (leading % Int::BITS) as u32;
85 let quire: &[Int] = value.as_int_array();
86 let idx_last = quire.len() - 1;
87
88 let value_width = Quire::<N, ES, SIZE>::BITS - leading;
96 if const { Int::BITS <= 8 }
97 && value_width > 2 * Quire::<N, ES, SIZE>::WIDTH + 1 {
98 return if quire[idx_last].is_positive() {Posit::MAX} else {Posit::MIN}
99 }
100 let exp = Int::of_u32(value_width) - Int::of_u32(Quire::<N, ES, SIZE>::WIDTH) - Int::ONE - Int::ONE;
101
102 let frac = {
122 let frac_hi = quire[idx_last - leading_ints] << leading_bits;
123 let frac_lo = if leading_bits != 0 && leading_ints < idx_last {
126 quire[idx_last - leading_ints - 1].lshr(Int::BITS - leading_bits)
127 } else {
128 Int::ZERO
129 };
130 frac_hi | frac_lo
131 };
132 let sticky = {
133 let sticky_hi = if leading_ints < idx_last {
135 quire[idx_last - leading_ints - 1] << leading_bits
136 } else {
137 Int::ZERO
138 };
139 let mut sticky_lo = Int::ZERO;
140 if leading_ints < idx_last - 1 {
141 for &i in &quire[.. idx_last - leading_ints - 2] {
142 sticky_lo |= i
143 }
144 }
145 sticky_hi | sticky_lo
146 };
147
148 unsafe { Decoded{frac, exp}.encode_regular_round(sticky) }
150 }
151}
152
153impl<
154 const N: u32,
155 const ES: u32,
156 Int: crate::Int,
157 const SIZE: usize,
158> RoundFrom<Quire<N, ES, SIZE>> for Posit<N, ES, Int> {
159 #[inline]
175 fn round_from(value: Quire<N, ES, SIZE>) -> Self {
176 Self::round_from(&value)
177 }
178}
179
180impl<
181 const N: u32,
182 const ES: u32,
183 Int: crate::Int,
184 const SIZE: usize,
185> From<Posit<N, ES, Int>> for Quire<N, ES, SIZE> {
186 fn from(value: Posit<N, ES, Int>) -> Self {
198 if value == Posit::ZERO {
199 Self::ZERO
200 } else if value == Posit::NAR {
201 Self::NAR
202 } else {
203 let mut quire = Self::ZERO;
204 let decoded = unsafe { value.decode_regular() };
206 unsafe { quire.add_posit_kernel(decoded) };
208 quire
209 }
210 }
211}
212
213#[cfg(test)]
214mod tests {
215 use super::*;
216 use malachite::rational::Rational;
217 use proptest::prelude::*;
218
219 #[test]
220 fn leading_run_3() {
221 let bytes = [
222 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
223 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
224 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
225 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0b00010000,
226 ];
227 assert_eq!(3, crate::q16::from_le_bytes(bytes).leading_run());
228 let bytes = [
229 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
230 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
231 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
232 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0b11100000,
233 ];
234 assert_eq!(3, crate::q16::from_le_bytes(bytes).leading_run());
235 }
236
237 #[test]
238 fn leading_run_1() {
239 let bytes = [
240 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
241 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
242 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
243 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0b01001101,
244 ];
245 assert_eq!(1, crate::q16::from_le_bytes(bytes).leading_run());
246 let bytes = [
247 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
248 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
249 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
250 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0b10000000,
251 ];
252 assert_eq!(1, crate::q16::from_le_bytes(bytes).leading_run());
253 assert_eq!(1, crate::q32::NAR.leading_run());
254 }
255
256 #[test]
257 fn leading_run_27() {
258 let bytes = [
259 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
260 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
261 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
262 0x00,0x11,0x22,0x33,0b00010111,0b00000000,0b00000000,0b00000000,
263 ];
264 assert_eq!(27, crate::q16::from_le_bytes(bytes).leading_run());
265 let bytes = [
266 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
267 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
268 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
269 0x00,0x11,0x22,0x33,0b11100111,0b11111111,0b11111111,0b11111111,
270 ];
271 assert_eq!(27, crate::q16::from_le_bytes(bytes).leading_run());
272 }
273
274 mod from_posit {
275 use super::*;
276
277 macro_rules! test_exhaustive {
278 ($name:ident, $posit:ty, $quire:ty) => {
279 #[test]
280 fn $name() {
281 for a in <$posit>::cases_exhaustive_all() {
282 assert_eq!(Rational::try_from(a), Rational::try_from(<$quire>::from(a)))
283 }
284 }
285 };
286 }
287
288 macro_rules! test_proptest {
289 ($name:ident, $posit:ty, $quire:ty) => {
290 proptest!{
291 #![proptest_config(ProptestConfig::with_cases(crate::PROPTEST_CASES))]
292 #[test]
293 fn $name(a in <$posit>::cases_proptest_all()) {
294 assert_eq!(Rational::try_from(a), Rational::try_from(<$quire>::from(a)))
295 }
296 }
297 };
298 }
299
300 test_exhaustive!{posit_10_0_exhaustive, Posit::<10, 0, i16>, Quire::<10, 0, 128>}
301 test_exhaustive!{posit_10_1_exhaustive, Posit::<10, 1, i16>, Quire::<10, 1, 128>}
302 test_exhaustive!{posit_10_2_exhaustive, Posit::<10, 2, i16>, Quire::<10, 2, 128>}
303 test_exhaustive!{posit_10_3_exhaustive, Posit::<10, 3, i16>, Quire::<10, 3, 128>}
304 test_exhaustive!{posit_8_0_exhaustive, Posit::<8, 0, i8>, Quire::<8, 0, 128>}
305
306 test_exhaustive!{p8_exhaustive, crate::p8, crate::q8}
307 test_exhaustive!{p16_exhaustive, crate::p16, crate::q16}
308 test_proptest!{p32_proptest, crate::p32, crate::q32}
309 test_proptest!{p64_proptest, crate::p64, crate::q64}
310
311 test_exhaustive!{posit_3_0_exhaustive, Posit::<3, 0, i8>, Quire::<3, 0, 128>}
312 test_exhaustive!{posit_4_0_exhaustive, Posit::<4, 0, i8>, Quire::<4, 0, 128>}
313 test_exhaustive!{posit_4_1_exhaustive, Posit::<4, 1, i8>, Quire::<4, 1, 128>}
314 }
315
316 mod from_quire {
317 use super::*;
318
319 macro_rules! test_proptest {
320 ($name:ident, $posit:ty, $quire:ty) => {
321 proptest!{
322 #![proptest_config(ProptestConfig::with_cases(crate::PROPTEST_CASES))]
323 #[test]
324 fn $name(q in <$quire>::cases_proptest_all()) {
325 let posit = <$posit>::round_from(&q);
326 let exact = Rational::try_from(q);
327 assert!(super::rational::try_is_correct_rounded(exact, posit))
328 }
329 }
330 };
331 }
332
333 test_proptest!{posit_10_0_proptest, Posit::<10, 0, i16>, Quire::<10, 0, 128>}
334 test_proptest!{posit_10_1_proptest, Posit::<10, 1, i16>, Quire::<10, 1, 128>}
335 test_proptest!{posit_10_2_proptest, Posit::<10, 2, i16>, Quire::<10, 2, 128>}
336 test_proptest!{posit_10_3_proptest, Posit::<10, 3, i16>, Quire::<10, 3, 128>}
337 test_proptest!{posit_8_0_proptest, Posit::<8, 0, i8>, Quire::<8, 0, 128>}
338
339 test_proptest!{p8_proptest, crate::p8, crate::q8}
340 test_proptest!{p16_proptest, crate::p16, crate::q16}
341 test_proptest!{p32_proptest, crate::p32, crate::q32}
342 test_proptest!{p64_proptest, crate::p64, crate::q64}
343
344 test_proptest!{posit_3_0_proptest, Posit::<3, 0, i8>, Quire::<3, 0, 128>}
345 test_proptest!{posit_4_0_proptest, Posit::<4, 0, i8>, Quire::<4, 0, 128>}
346 test_proptest!{posit_4_1_proptest, Posit::<4, 1, i8>, Quire::<4, 1, 128>}
347 }
348
349 mod roundtrip {
350 use super::*;
351
352 macro_rules! test_exhaustive {
353 ($name:ident, $posit:ty, $quire:ty) => {
354 #[test]
355 fn $name() {
356 for p in <$posit>::cases_exhaustive_all() {
357 assert_eq!(p, <$posit>::round_from(&<$quire>::from(p)))
358 }
359 }
360 };
361 }
362
363 macro_rules! test_proptest {
364 ($name:ident, $posit:ty, $quire:ty) => {
365 proptest!{
366 #![proptest_config(ProptestConfig::with_cases(crate::PROPTEST_CASES))]
367 #[test]
368 fn $name(p in <$posit>::cases_proptest_all()) {
369 assert_eq!(p, <$posit>::round_from(&<$quire>::from(p)))
370 }
371 }
372 };
373 }
374
375 test_exhaustive!{posit_10_0_exhaustive, Posit::<10, 0, i16>, Quire::<10, 0, 128>}
376 test_exhaustive!{posit_10_1_exhaustive, Posit::<10, 1, i16>, Quire::<10, 1, 128>}
377 test_exhaustive!{posit_10_2_exhaustive, Posit::<10, 2, i16>, Quire::<10, 2, 128>}
378 test_exhaustive!{posit_10_3_exhaustive, Posit::<10, 3, i16>, Quire::<10, 3, 128>}
379 test_exhaustive!{posit_8_0_exhaustive, Posit::<8, 0, i8>, Quire::<8, 0, 128>}
380
381 test_exhaustive!{p8_exhaustive, crate::p8, crate::q8}
382 test_exhaustive!{p16_exhaustive, crate::p16, crate::q16}
383 test_proptest!{p32_proptest, crate::p32, crate::q32}
384 test_proptest!{p64_proptest, crate::p64, crate::q64}
385
386 test_exhaustive!{posit_3_0_exhaustive, Posit::<3, 0, i8>, Quire::<3, 0, 128>}
387 test_exhaustive!{posit_4_0_exhaustive, Posit::<4, 0, i8>, Quire::<4, 0, 128>}
388 test_exhaustive!{posit_4_1_exhaustive, Posit::<4, 1, i8>, Quire::<4, 1, 128>}
389 }
390}