1use super::*;
2use crate::underlying::const_as;
3
4impl<
5 const N1: u32,
6 const ES1: u32,
7 Int1: crate::Int,
8 const RS1: u32,
9> Posit<N1, ES1, Int1, RS1> {
10 fn round_from_fast<
12 const N2: u32,
13 const ES2: u32,
14 Int2: crate::Int,
15 const RS2: u32,
16 >(self) -> Posit<N2, ES2, Int2, RS2> {
17 if const { ES1 != ES2 || RS1 != RS2 } { unimplemented!() }
18 if const { N1 <= N2 } {
19 let bits = const_as::<Int1, Int2>(self.to_bits()) << (N2 - N1);
21 unsafe { Posit::from_bits_unchecked(bits) }
24 } else {
25 let sticky: Int2 = Int2::from(self.to_bits().mask_lsb(N1 - N2 - 1) != Int1::ZERO);
29 let round: Int2 = const_as(self.to_bits() >> (N1 - N2 - 1));
30 let bits = const_as::<Int1, Int2>(self.to_bits() >> (N1 - N2));
43 let round_up = round & (bits | sticky) & Int2::ONE;
44 let is_special = Posit::<N2, ES2, Int2, RS2>::from_bits(bits).is_special();
52 let round_up = round_up | ((round | sticky) & Int2::from(is_special));
53 let bits_rounded = Posit::<N2, ES2, Int2, RS2>::sign_extend(bits.wrapping_add(round_up));
54 let overflow = !(bits_rounded ^ bits).is_positive();
55 Posit::from_bits(bits_rounded.wrapping_sub(Int2::from(overflow)))
56 }
57 }
58
59 fn round_from_slow<
61 const N2: u32,
62 const ES2: u32,
63 Int2: crate::Int,
64 const RS2: u32,
65 >(self) -> Posit<N2, ES2, Int2, RS2> {
66 if self == Self::ZERO {
67 Posit::ZERO
68 } else if self == Self::NAR {
69 Posit::NAR
70 } else {
71 let decoded = unsafe { self.decode_regular() };
73 let shift_right = if const { Int1::BITS <= Int2::BITS } {0} else {Int1::BITS - Int2::BITS};
75 let shift_left = if const { Int1::BITS >= Int2::BITS } {0} else {Int2::BITS - Int1::BITS};
76 let frac = const_as::<Int1, Int2>(decoded.frac >> shift_right) << shift_left;
77 let exp = const_as::<Int1, Int2>(decoded.exp);
78 let sticky = Int2::from(decoded.frac.mask_lsb(shift_right) != Int1::ZERO);
80 if Int1::BITS > Int2::BITS
83 && Self::MAX_EXP >= const_as(Decoded::<N2, ES2, N2, Int2>::FRAC_DENOM)
84 && decoded.exp.abs() >= const_as(Decoded::<N2, ES2, N2, Int2>::FRAC_DENOM) {
85 let exp = Decoded::<N2, ES2, N2, Int2>::FRAC_DENOM - Int2::ONE;
87 let exp = if decoded.exp.is_positive() {exp} else {-exp};
88 return unsafe { Decoded{frac, exp}.encode_regular() }
91 }
92 unsafe { Decoded{frac, exp}.encode_regular_round(sticky) }
96 }
97 }
98}
99
100impl<
111 const N: u32,
112 const ES: u32,
113 Int: crate::Int,
114 const RS: u32,
115> Posit<N, ES, Int, RS> {
116 pub fn convert<
134 const N2: u32,
135 const ES2: u32,
136 Int2: crate::Int,
137 const RS2: u32,
138 >(self) -> Posit<N2, ES2, Int2, RS2> {
139 if const { ES == ES2 && RS == RS2 } {
140 self.round_from_fast()
143 } else {
144 self.round_from_slow()
146 }
147 }
148}
149
150#[cfg(test)]
151#[allow(non_camel_case_types)]
152mod tests {
153 use super::*;
154 use malachite::rational::Rational;
155 use proptest::prelude::*;
156
157 macro_rules! test_exhaustive {
158 ($name: ident, $src:ty, $dst:ty) => {
159 #[test]
160 fn $name() {
161 for src in <$src>::cases_exhaustive_all() {
162 let dst: $dst = src.convert();
163 assert!(super::rational::try_is_correct_rounded(Rational::try_from(src), dst))
164 }
165 }
166 };
167 }
168
169 macro_rules! test_proptest {
170 ($name: ident, $src:ty, $dst:ty) => {
171 proptest!{
172 #![proptest_config(ProptestConfig::with_cases(crate::PROPTEST_CASES))]
173 #[test]
174 fn $name(src in <$src>::cases_proptest_all()) {
175 let dst: $dst = src.convert();
176 assert!(super::rational::try_is_correct_rounded(Rational::try_from(src), dst))
177 }
178 }
179 };
180 }
181
182 macro_rules! suite_exhaustive {
183 ($name_src:ident, $src:ty) => {
184 mod $name_src {
185 use super::*;
186 test_exhaustive!{posit_10_0_exhaustive, $src, Posit<10, 0, i16>}
187 test_exhaustive!{posit_10_1_exhaustive, $src, Posit<10, 1, i16>}
188 test_exhaustive!{posit_10_2_exhaustive, $src, Posit<10, 2, i16>}
189 test_exhaustive!{posit_10_3_exhaustive, $src, Posit<10, 3, i16>}
190 test_exhaustive!{posit_8_0_exhaustive, $src, Posit<8, 0, i8>}
191 test_exhaustive!{posit_20_4_exhaustive, $src, Posit<20, 4, i32>}
192 test_exhaustive!{p8_exhaustive, $src, crate::p8}
193 test_exhaustive!{p16_exhaustive, $src, crate::p16}
194 test_exhaustive!{p32_exhaustive, $src, crate::p32}
195 test_exhaustive!{p64_exhaustive, $src, crate::p64}
196 test_exhaustive!{posit_3_0_exhaustive, $src, Posit<3, 0, i8>}
197 test_exhaustive!{posit_4_0_exhaustive, $src, Posit<4, 0, i8>}
198 test_exhaustive!{posit_4_1_exhaustive, $src, Posit<4, 1, i8>}
199 test_exhaustive!{bposit_8_3_6_exhaustive, $src, Posit::<8, 3, i8, 6>}
200 test_exhaustive!{bposit_16_5_6_exhaustive, $src, Posit::<16, 5, i16, 6>}
201 test_exhaustive!{bposit_32_5_6_exhaustive, $src, Posit::<32, 5, i32, 6>}
202 test_exhaustive!{bposit_64_5_6_exhaustive, $src, Posit::<64, 5, i64, 6>}
203 test_exhaustive!{bposit_10_2_6_exhaustive, $src, Posit::<10, 2, i16, 6>}
204 test_exhaustive!{bposit_10_2_7_exhaustive, $src, Posit::<10, 2, i16, 7>}
205 test_exhaustive!{bposit_10_2_8_exhaustive, $src, Posit::<10, 2, i16, 8>}
206 test_exhaustive!{bposit_10_2_9_exhaustive, $src, Posit::<10, 2, i16, 9>}
207 }
208 };
209 }
210
211 macro_rules! suite_proptest {
212 ($name_src:ident, $src:ty) => {
213 mod $name_src {
214 use super::*;
215 test_proptest!{posit_10_0_proptest, $src, Posit<10, 0, i16>}
216 test_proptest!{posit_10_1_proptest, $src, Posit<10, 1, i16>}
217 test_proptest!{posit_10_2_proptest, $src, Posit<10, 2, i16>}
218 test_proptest!{posit_10_3_proptest, $src, Posit<10, 3, i16>}
219 test_proptest!{posit_8_0_proptest, $src, Posit<8, 0, i8>}
220 test_proptest!{posit_20_4_proptest, $src, Posit<20, 4, i32>}
221 test_proptest!{p8_proptest, $src, crate::p8}
222 test_proptest!{p16_proptest, $src, crate::p16}
223 test_proptest!{p32_proptest, $src, crate::p32}
224 test_proptest!{p64_proptest, $src, crate::p64}
225 test_proptest!{posit_3_0_proptest, $src, Posit<3, 0, i8>}
226 test_proptest!{posit_4_0_proptest, $src, Posit<4, 0, i8>}
227 test_proptest!{posit_4_1_proptest, $src, Posit<4, 1, i8>}
228 test_proptest!{bposit_8_3_6_proptest, $src, Posit::<8, 3, i8, 6>}
229 test_proptest!{bposit_16_5_6_proptest, $src, Posit::<16, 5, i16, 6>}
230 test_proptest!{bposit_32_5_6_proptest, $src, Posit::<32, 5, i32, 6>}
231 test_proptest!{bposit_64_5_6_proptest, $src, Posit::<64, 5, i64, 6>}
232 test_proptest!{bposit_10_2_6_proptest, $src, Posit::<10, 2, i16, 6>}
233 test_proptest!{bposit_10_2_7_proptest, $src, Posit::<10, 2, i16, 7>}
234 test_proptest!{bposit_10_2_8_proptest, $src, Posit::<10, 2, i16, 8>}
235 test_proptest!{bposit_10_2_9_proptest, $src, Posit::<10, 2, i16, 9>}
236 }
237 };
238 }
239
240 suite_exhaustive!{posit_10_0, Posit<10, 0, i16>}
241 suite_exhaustive!{posit_10_1, Posit<10, 1, i16>}
242 suite_exhaustive!{posit_10_2, Posit<10, 2, i16>}
243 suite_exhaustive!{posit_10_3, Posit<10, 3, i16>}
244
245 suite_exhaustive!{posit_8_0, Posit<8, 0, i8>}
246 suite_exhaustive!{posit_20_4, Posit<20, 4, i32>}
247
248 suite_exhaustive!{p8, crate::p8}
249 suite_exhaustive!{p16, crate::p16}
250 suite_proptest!{p32, crate::p32}
251 suite_proptest!{p64, crate::p64}
252
253 suite_exhaustive!{posit_3_0, Posit<3, 0, i8>}
254 suite_exhaustive!{posit_4_0, Posit<4, 0, i8>}
255 suite_exhaustive!{posit_4_1, Posit<4, 1, i8>}
256
257 suite_exhaustive!{bposit_8_3_6_exhaustive, Posit::<8, 3, i8, 6>}
258 suite_exhaustive!{bposit_16_5_6_exhaustive, Posit::<16, 5, i16, 6>}
259 suite_proptest!{bposit_32_5_6_proptest, Posit::<32, 5, i32, 6>}
260 suite_proptest!{bposit_64_5_6_proptest, Posit::<64, 5, i64, 6>}
261
262 suite_exhaustive!{bposit_10_2_6_exhaustive, Posit::<10, 2, i16, 6>}
263 suite_exhaustive!{bposit_10_2_7_exhaustive, Posit::<10, 2, i16, 7>}
264 suite_exhaustive!{bposit_10_2_8_exhaustive, Posit::<10, 2, i16, 8>}
265 suite_exhaustive!{bposit_10_2_9_exhaustive, Posit::<10, 2, i16, 9>}
266}