fast_posit/posit/convert/
int.rs1use super::*;
2
3use crate::underlying::const_as;
4
5#[inline]
9unsafe fn round_from_signed_kernel<
10 FromInt: crate::Int,
11 const N: u32,
12 const ES: u32,
13 Int: crate::Int,
14>(int: FromInt) -> (Decoded<N, ES, Int>, Int) {
15 let shift_right = if const { Int::BITS >= FromInt::BITS } {0} else {FromInt::BITS - Int::BITS};
19
20 let shift_left = if const { Int::BITS <= FromInt::BITS } {0} else {Int::BITS - FromInt::BITS};
23
24 let underflow = unsafe { int.leading_run_minus_one() };
41 let frac = const_as::<FromInt, Int>(int << underflow >> shift_right) << shift_left;
42 let exp = const_as::<i32, Int>(Decoded::<N, ES, FromInt>::FRAC_WIDTH.wrapping_sub(underflow) as i32);
43 let sticky = Int::from(int.mask_lsb(shift_right.saturating_sub(underflow)) != FromInt::ZERO);
44
45 (Decoded{frac, exp}, sticky)
46}
47
48#[inline]
49fn round_from_signed<
50 FromInt: crate::Int,
51 const N: u32,
52 const ES: u32,
53 Int: crate::Int,
54>(int: FromInt) -> Posit<N, ES, Int> {
55 if int == FromInt::ZERO { return Posit::ZERO }
58 if int == FromInt::MIN { return Posit::NAR }
59
60 if const { FromInt::BITS as i128 > 1 << Decoded::<N, ES, Int>::FRAC_WIDTH } {
63 let limit = FromInt::ONE << (1 << Decoded::<N, ES, Int>::FRAC_WIDTH);
64 if int >= limit { return Posit::MAX }
65 if int <= -limit { return Posit::MIN }
66 }
67
68 let (result, sticky) = unsafe { round_from_signed_kernel(int) };
70 unsafe { result.encode_regular_round(sticky) }
72}
73
74macro_rules! make_impl {
75 ($t:ty) => {
76 impl<
77 const N: u32,
78 const ES: u32,
79 Int: crate::Int,
80 > RoundFrom<$t> for Posit<N, ES, Int> {
81 #[doc = concat!("Convert an `", stringify!($t), "` into a `Posit`, [rounding according to the standard]:")]
82 #[doc = ""]
83 #[doc = concat!(" - If the value is [`", stringify!($t), "::MIN`] (i.e. the value where the most significant bit is 1 and the rest are 0), it converts to [`NaR`](Posit::NAR).")]
84 #[doc = " - Otherwise, the integer value is rounded (if necessary)."]
85 #[doc = ""]
86 #[doc = "[rounding according to the standard]: https://posithub.org/docs/posit_standard-2.pdf#subsection.6.4"]
87 fn round_from(value: $t) -> Self {
88 round_from_signed(value)
89 }
90 }
91 }
92}
93
94make_impl!{i8}
95make_impl!{i16}
96make_impl!{i32}
97make_impl!{i64}
98make_impl!{i128}
99
100#[cfg(test)]
103mod tests {
104 use super::*;
105 use malachite::rational::Rational;
106 use proptest::prelude::*;
107
108 fn is_correct_rounded<FromInt: crate::Int, const N: u32, const ES: u32, Int: crate::Int>(
110 int: FromInt,
111 ) -> bool
112 where
113 FromInt: Into<Rational> + RoundInto<Posit<N, ES, Int>>,
114 Rational: TryFrom<Posit<N, ES, Int>>,
115 <Rational as TryFrom<Posit<N, ES, Int>>>::Error: core::fmt::Debug
116 {
117 let posit: Posit<N, ES, Int> = int.round_into();
118 if int == FromInt::MIN {
119 posit == Posit::NAR
120 } else {
121 let exact: Rational = int.into();
122 super::rational::is_correct_rounded(exact, posit)
123 }
124 }
125
126 macro_rules! make_exhaustive {
127 ($t:ident) => {
128 mod $t {
129 use super::*;
130
131 #[test]
132 fn posit_10_0_exhaustive() {
133 for int in $t::MIN ..= $t::MAX {
134 assert!(is_correct_rounded::<$t, 10, 0, i16>(int), "{:?}", int)
135 }
136 }
137
138 #[test]
139 fn posit_10_1_exhaustive() {
140 for int in $t::MIN ..= $t::MAX {
141 assert!(is_correct_rounded::<$t, 10, 1, i16>(int), "{:?}", int)
142 }
143 }
144
145 #[test]
146 fn posit_10_2_exhaustive() {
147 for int in $t::MIN ..= $t::MAX {
148 assert!(is_correct_rounded::<$t, 10, 2, i16>(int), "{:?}", int)
149 }
150 }
151
152 #[test]
153 fn posit_10_3_exhaustive() {
154 for int in $t::MIN ..= $t::MAX {
155 assert!(is_correct_rounded::<$t, 10, 3, i16>(int), "{:?}", int)
156 }
157 }
158
159 #[test]
160 fn posit_8_0_exhaustive() {
161 for int in $t::MIN ..= $t::MAX {
162 assert!(is_correct_rounded::<$t, 8, 0, i8>(int), "{:?}", int)
163 }
164 }
165
166 #[test]
167 fn p8_exhaustive() {
168 for int in $t::MIN ..= $t::MAX {
169 assert!(is_correct_rounded::<$t, 8, 2, i8>(int), "{:?}", int)
170 }
171 }
172
173 #[test]
174 fn p16_exhaustive() {
175 for int in $t::MIN ..= $t::MAX {
176 assert!(is_correct_rounded::<$t, 16, 2, i16>(int), "{:?}", int)
177 }
178 }
179
180 #[test]
181 fn p32_exhaustive() {
182 for int in $t::MIN ..= $t::MAX {
183 assert!(is_correct_rounded::<$t, 32, 2, i32>(int), "{:?}", int)
184 }
185 }
186
187 #[test]
188 fn p64_exhaustive() {
189 for int in $t::MIN ..= $t::MAX {
190 assert!(is_correct_rounded::<$t, 64, 2, i64>(int), "{:?}", int)
191 }
192 }
193 }
194 }
195 }
196
197 macro_rules! make_proptest {
198 ($t:ident) => {
199 mod $t {
200 use super::*;
201
202 const PROPTEST_CASES: u32 = if cfg!(debug_assertions) {0x1_0000} else {0x80_0000};
203 proptest!{
204 #![proptest_config(ProptestConfig::with_cases(PROPTEST_CASES))]
205
206 #[test]
207 fn posit_10_0_proptest(int in any::<$t>()) {
208 assert!(is_correct_rounded::<$t, 10, 0, i16>(int), "{:?}", int)
209 }
210
211 #[test]
212 fn posit_10_1_proptest(int in any::<$t>()) {
213 assert!(is_correct_rounded::<$t, 10, 1, i16>(int), "{:?}", int)
214 }
215
216 #[test]
217 fn posit_10_2_proptest(int in any::<$t>()) {
218 assert!(is_correct_rounded::<$t, 10, 2, i16>(int), "{:?}", int)
219 }
220
221 #[test]
222 fn posit_10_3_proptest(int in any::<$t>()) {
223 assert!(is_correct_rounded::<$t, 10, 3, i16>(int), "{:?}", int)
224 }
225
226 #[test]
227 fn posit_8_0_proptest(int in any::<$t>()) {
228 assert!(is_correct_rounded::<$t, 8, 0, i8>(int), "{:?}", int)
229 }
230
231 #[test]
232 fn p8_proptest(int in any::<$t>()) {
233 assert!(is_correct_rounded::<$t, 8, 2, i8>(int), "{:?}", int)
234 }
235
236 #[test]
237 fn p16_proptest(int in any::<$t>()) {
238 assert!(is_correct_rounded::<$t, 16, 2, i16>(int), "{:?}", int)
239 }
240
241 #[test]
242 fn p32_proptest(int in any::<$t>()) {
243 assert!(is_correct_rounded::<$t, 32, 2, i32>(int), "{:?}", int)
244 }
245
246 #[test]
247 fn p64_proptest(int in any::<$t>()) {
248 assert!(is_correct_rounded::<$t, 64, 2, i64>(int), "{:?}", int)
249 }
250 }
251 }
252 }
253 }
254
255 make_exhaustive!{i8}
256 make_exhaustive!{i16}
257 make_proptest!{i32}
258 make_proptest!{i64}
259 make_proptest!{i128}
260}