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: &[i64] = self.as_int_array();
12 let leading = quire[0];
13 match leading {
14 0 => {
15 for i in 1 .. quire.len() {
16 if quire[i] != 0 {
17 return i as u32 * 64 + quire[i].to_be().leading_zeros()
18 }
19 }
20 return quire.len() as u32 * 64
21 },
22 -1 => {
23 for i in 1 .. quire.len() {
24 if quire[i] != -1 {
25 return i as u32 * 64 + quire[i].to_be().leading_ones()
26 }
27 }
28 return quire.len() as u32 * 64
29 },
30 _ => {
31 if leading << 1 == 0 {
32 1
33 } else {
34 use crate::underlying::Sealed;
35 unsafe { leading.to_be().leading_run_minus_one() + 1 }
36 }
37 },
38 }
39 }
40}
41
42impl<
43 const N: u32,
44 const ES: u32,
45 Int: crate::Int,
46 const SIZE: usize,
47> RoundFrom<&'_ Quire<N, ES, SIZE>> for Posit<N, ES, Int> {
48 fn round_from(value: &'_ Quire<N, ES, SIZE>) -> Self {
64 let leading = value.leading_run();
67 if leading == 1 && value.is_nar() { return Posit::NAR }
69
70 let leading_ints = leading / Int::BITS;
80 let leading_bits = leading % Int::BITS;
81 let quire: &[Int] = value.as_int_array();
82
83 let value_width = Quire::<N, ES, SIZE>::BITS - leading;
91 if const { Quire::<N, ES, SIZE>::PROD_LIMIT >= 64 } {
92 if value_width > 2 * Quire::<N, ES, SIZE>::WIDTH + 1 {
93 return if quire[0].to_be().is_positive() {Posit::MAX} else {Posit::MIN}
94 }
95 }
96 let exp = Int::of_u32(value_width) - Int::of_u32(Quire::<N, ES, SIZE>::WIDTH) - Int::ONE;
97
98 let frac =
121 if leading_bits == 0 {
122 if leading_ints as usize == quire.len() {
125 return unsafe { Posit::from_bits_unchecked(quire[0]) }
128 }
129 let frac_hi = quire[leading_ints as usize - 1] << (Int::BITS - 1);
130 let frac_lo = quire[leading_ints as usize].to_be().lshr(1);
131 frac_hi | frac_lo
132 } else {
133 let frac_hi = quire[leading_ints as usize].to_be() << (leading_bits - 1);
136 if leading_ints as usize == quire.len() - 1 {
137 return unsafe { Decoded{frac: frac_hi, exp}.encode_regular() }
139 }
140 let frac_lo = if leading_bits == 1 {Int::ZERO} else {quire[leading_ints as usize + 1].to_be().lshr(Int::BITS - leading_bits + 1)};
141 frac_hi | frac_lo
142 };
143 let sticky = {
144 if leading_ints as usize == quire.len() - 1 {
145 Int::ZERO
146 } else {
147 let sticky_hi = quire[leading_ints as usize + 1].to_be() << leading_bits;
148 let mut sticky_lo = Int::ZERO;
149 for &i in &quire[leading_ints as usize + 1 ..] {
150 sticky_lo |= i
151 }
152 sticky_hi | sticky_lo | (quire[leading_ints as usize].to_be() & Int::from(leading_bits == 0))
153 }
154 };
155
156 unsafe { Decoded{frac, exp}.encode_regular_round(sticky) }
158 }
159}
160
161impl<
178 const N: u32,
179 const ES: u32,
180 Int: crate::Int,
181 const SIZE: usize,
182> From<Posit<N, ES, Int>> for Quire<N, ES, SIZE> {
183 fn from(value: Posit<N, ES, Int>) -> Self {
195 if value == Posit::ZERO {
196 Self::ZERO
197 } else if value == Posit::NAR {
198 Self::NAR
199 } else {
200 let mut quire = Self::ZERO;
201 let decoded = unsafe { value.decode_regular() };
203 unsafe { quire.accumulate_decoded(decoded) };
205 quire
206 }
207 }
208}
209
210#[cfg(test)]
211mod tests {
212 use super::*;
213 use malachite::rational::Rational;
214 use proptest::prelude::*;
215
216 mod from_posit {
217 use super::*;
218
219 macro_rules! test_exhaustive {
220 ($name:ident, $posit:ty, $quire:ty) => {
221 #[test]
222 fn $name() {
223 for a in <$posit>::cases_exhaustive_all() {
224 assert_eq!(Rational::try_from(a), Rational::try_from(<$quire>::from(a)))
225 }
226 }
227 };
228 }
229
230 macro_rules! test_proptest {
231 ($name:ident, $posit:ty, $quire:ty) => {
232 proptest!{
233 #![proptest_config(ProptestConfig::with_cases(crate::PROPTEST_CASES))]
234 #[test]
235 fn $name(a in <$posit>::cases_proptest_all()) {
236 assert_eq!(Rational::try_from(a), Rational::try_from(<$quire>::from(a)))
237 }
238 }
239 };
240 }
241
242 test_exhaustive!{posit_10_0_exhaustive, Posit::<10, 0, i16>, Quire::<10, 0, 128>}
243 test_exhaustive!{posit_10_1_exhaustive, Posit::<10, 1, i16>, Quire::<10, 1, 128>}
244 test_exhaustive!{posit_10_2_exhaustive, Posit::<10, 2, i16>, Quire::<10, 2, 128>}
245 test_exhaustive!{posit_10_3_exhaustive, Posit::<10, 3, i16>, Quire::<10, 3, 128>}
246 test_exhaustive!{posit_8_0_exhaustive, Posit::<8, 0, i8>, Quire::<8, 0, 128>}
247
248 test_exhaustive!{p8_exhaustive, crate::p8, crate::q8}
249 test_exhaustive!{p16_exhaustive, crate::p16, crate::q16}
250 test_proptest!{p32_proptest, crate::p32, crate::q32}
251 test_proptest!{p64_proptest, crate::p64, crate::q64}
252
253 test_exhaustive!{posit_3_0_exhaustive, Posit::<3, 0, i8>, Quire::<3, 0, 128>}
254 test_exhaustive!{posit_4_0_exhaustive, Posit::<4, 0, i8>, Quire::<4, 0, 128>}
255 test_exhaustive!{posit_4_1_exhaustive, Posit::<4, 1, i8>, Quire::<4, 1, 128>}
256 }
257
258 mod from_quire {
259 use super::*;
260
261 macro_rules! test_proptest {
262 ($name:ident, $posit:ty, $quire:ty) => {
263 proptest!{
264 #![proptest_config(ProptestConfig::with_cases(crate::PROPTEST_CASES))]
265 #[test]
266 fn $name(q in <$quire>::cases_proptest_all()) {
267 let posit = <$posit>::round_from(&q);
268 let exact = Rational::try_from(q);
269 assert!(super::rational::try_is_correct_rounded(exact, posit))
270 }
271 }
272 };
273 }
274
275 test_proptest!{posit_10_0_proptest, Posit::<10, 0, i16>, Quire::<10, 0, 128>}
276 test_proptest!{posit_10_1_proptest, Posit::<10, 1, i16>, Quire::<10, 1, 128>}
277 test_proptest!{posit_10_2_proptest, Posit::<10, 2, i16>, Quire::<10, 2, 128>}
278 test_proptest!{posit_10_3_proptest, Posit::<10, 3, i16>, Quire::<10, 3, 128>}
279 test_proptest!{posit_8_0_proptest, Posit::<8, 0, i8>, Quire::<8, 0, 128>}
280
281 test_proptest!{p8_proptest, crate::p8, crate::q8}
282 test_proptest!{p16_proptest, crate::p16, crate::q16}
283 test_proptest!{p32_proptest, crate::p32, crate::q32}
284 test_proptest!{p64_proptest, crate::p64, crate::q64}
285
286 test_proptest!{posit_3_0_proptest, Posit::<3, 0, i8>, Quire::<3, 0, 128>}
287 test_proptest!{posit_4_0_proptest, Posit::<4, 0, i8>, Quire::<4, 0, 128>}
288 test_proptest!{posit_4_1_proptest, Posit::<4, 1, i8>, Quire::<4, 1, 128>}
289 }
290
291 mod roundtrip {
292 use super::*;
293
294 macro_rules! test_exhaustive {
295 ($name:ident, $posit:ty, $quire:ty) => {
296 #[test]
297 fn $name() {
298 for p in <$posit>::cases_exhaustive_all() {
299 assert_eq!(p, <$posit>::round_from(&<$quire>::from(p)))
300 }
301 }
302 };
303 }
304
305 macro_rules! test_proptest {
306 ($name:ident, $posit:ty, $quire:ty) => {
307 proptest!{
308 #![proptest_config(ProptestConfig::with_cases(crate::PROPTEST_CASES))]
309 #[test]
310 fn $name(p in <$posit>::cases_proptest_all()) {
311 assert_eq!(p, <$posit>::round_from(&<$quire>::from(p)))
312 }
313 }
314 };
315 }
316
317 test_exhaustive!{posit_10_0_exhaustive, Posit::<10, 0, i16>, Quire::<10, 0, 128>}
318 test_exhaustive!{posit_10_1_exhaustive, Posit::<10, 1, i16>, Quire::<10, 1, 128>}
319 test_exhaustive!{posit_10_2_exhaustive, Posit::<10, 2, i16>, Quire::<10, 2, 128>}
320 test_exhaustive!{posit_10_3_exhaustive, Posit::<10, 3, i16>, Quire::<10, 3, 128>}
321 test_exhaustive!{posit_8_0_exhaustive, Posit::<8, 0, i8>, Quire::<8, 0, 128>}
322
323 test_exhaustive!{p8_exhaustive, crate::p8, crate::q8}
324 test_exhaustive!{p16_exhaustive, crate::p16, crate::q16}
325 test_proptest!{p32_proptest, crate::p32, crate::q32}
326 test_proptest!{p64_proptest, crate::p64, crate::q64}
327
328 test_exhaustive!{posit_3_0_exhaustive, Posit::<3, 0, i8>, Quire::<3, 0, 128>}
329 test_exhaustive!{posit_4_0_exhaustive, Posit::<4, 0, i8>, Quire::<4, 0, 128>}
330 test_exhaustive!{posit_4_1_exhaustive, Posit::<4, 1, i8>, Quire::<4, 1, 128>}
331 }
332}