1use super::*;
2
3use crate::underlying::const_as;
4
5fn decode_finite_f64<
8 const N: u32,
9 const ES: u32,
10 Int: crate::Int,
11>(num: f64) -> (Decoded<N, ES, Int>, Int) { debug_assert!(num.is_finite());
13 const MANTISSA_DIGITS_EXPLICIT: u32 = f64::MANTISSA_DIGITS - 1;
14 const EXP_BIAS: i64 = f64::MIN_EXP as i64 - 1;
15 const HIDDEN_BIT: i64 = (i64::MIN as u64 >> 1) as i64;
16
17 use crate::underlying::Sealed;
19 let sign = num.is_sign_positive();
20 let bits = num.abs().to_bits() as i64;
21 let mantissa = bits.mask_lsb(MANTISSA_DIGITS_EXPLICIT);
22 let mut exponent = bits >> MANTISSA_DIGITS_EXPLICIT;
23
24 let is_normal = exponent != 0;
27 exponent -= i64::from(is_normal);
28
29 let frac: i64 = {
35 const SHIFT_LEFT: u32 = 64 - MANTISSA_DIGITS_EXPLICIT - 2;
36 let unsigned_frac = (mantissa << SHIFT_LEFT) | HIDDEN_BIT;
37 if sign {
38 unsigned_frac
39 } else if mantissa != 0 {
40 -unsigned_frac
41 } else {
42 exponent -= 1;
43 i64::MIN
44 }
45 };
46 let (mut frac, sticky): (Int, Int) = {
50 let shift_left = Int::BITS as i64 - 64;
51 if shift_left >= 0 {
52 let shift_left = shift_left as u32;
54 let frac = const_as::<i64, Int>(frac) << shift_left;
55 (frac, Int::ZERO)
56 } else {
57 let shift_right = -shift_left as u32;
59 let sticky = Int::from(frac.mask_lsb(shift_right) != 0);
60 let frac = const_as::<i64, Int>(frac.lshr(shift_right));
61 (frac, sticky)
62 }
63 };
64
65 if !is_normal {
79 if frac == Int::ZERO {
80 return (Decoded { frac: Int::ONE, exp: Int::MIN >> 1 }, Int::ZERO)
81 }
82 let underflow = unsafe { frac.leading_run_minus_one() };
84 frac = frac << underflow;
85 exponent = exponent.wrapping_sub(underflow as i64);
86 }
87
88 let exponent = exponent.wrapping_add(EXP_BIAS);
93 let exp =
94 if const { Int::BITS < 64 } && exponent > const_as::<Int, i64>(Int::MAX >> 1) {
95 Int::MAX >> 1
96 } else if const { Int::BITS < 64 } && exponent < const_as::<Int, i64>(Int::MIN >> 1) {
97 Int::MIN >> 1
98 } else {
99 const_as::<_, Int>(exponent)
100 };
101
102 (Decoded { exp, frac }, sticky)
103}
104
105fn decode_finite_f32<
108 const N: u32,
109 const ES: u32,
110 Int: crate::Int,
111>(num: f32) -> (Decoded<N, ES, Int>, Int) {
112 debug_assert!(num.is_finite());
113 decode_finite_f64(num.into())
116}
117
118impl<
119 const N: u32,
120 const ES: u32,
121 Int: crate::Int,
122> RoundFrom<f32> for Posit<N, ES, Int> {
123 fn round_from(value: f32) -> Self {
130 use core::num::FpCategory;
131 match value.classify() {
132 FpCategory::Nan | FpCategory::Infinite => Self::NAR,
133 FpCategory::Zero => Self::ZERO,
134 FpCategory::Normal | FpCategory::Subnormal => {
135 let (decoded, sticky) = decode_finite_f32(value);
136 unsafe { decoded.encode_regular_round(sticky) }
137 }
138 }
139 }
140}
141
142impl<
143 const N: u32,
144 const ES: u32,
145 Int: crate::Int,
146> RoundFrom<f64> for Posit<N, ES, Int> {
147 fn round_from(value: f64) -> Self {
154 use core::num::FpCategory;
155 match value.classify() {
156 FpCategory::Nan | FpCategory::Infinite => Self::NAR,
157 FpCategory::Zero => Self::ZERO,
158 FpCategory::Normal | FpCategory::Subnormal => {
159 let (decoded, sticky) = decode_finite_f64(value);
160 unsafe { decoded.encode_regular_round(sticky) }
161 }
162 }
163 }
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169
170 use malachite::rational::Rational;
171 use proptest::prelude::*;
172
173 mod f64 {
174 use super::*;
175
176 fn is_correct_rounded<const N: u32, const ES: u32, Int: crate::Int>(float: f64) -> bool
178 where
179 Rational: From<Decoded<N, ES, Int>> + TryFrom<Posit<N, ES, Int>> + TryFrom<f64>,
180 <Rational as TryFrom<Posit<N, ES, Int>>>::Error: core::fmt::Debug
181 {
182 let posit = Posit::<N, ES, Int>::round_from(float);
183 match Rational::try_from(float) {
184 Ok(exact) => super::rational::is_correct_rounded(exact, posit),
185 Err(_) => posit == Posit::NAR,
186 }
187 }
188
189 #[test]
190 fn zero() {
191 assert_eq!(crate::p8::round_from(0.0f64), crate::p8::ZERO);
192 assert_eq!(crate::p16::round_from(0.0f64), crate::p16::ZERO);
193 assert_eq!(crate::p32::round_from(0.0f64), crate::p32::ZERO);
194 assert_eq!(crate::p64::round_from(0.0f64), crate::p64::ZERO);
195 assert_eq!(Posit::<8, 0, i8>::round_from(0.0f64), Posit::<8, 0, i8>::ZERO);
196 assert_eq!(Posit::<10, 0, i16>::round_from(0.0f64), Posit::<10, 0, i16>::ZERO);
197 assert_eq!(Posit::<10, 1, i16>::round_from(0.0f64), Posit::<10, 1, i16>::ZERO);
198 assert_eq!(Posit::<10, 2, i16>::round_from(0.0f64), Posit::<10, 2, i16>::ZERO);
199 assert_eq!(Posit::<10, 3, i16>::round_from(0.0f64), Posit::<10, 3, i16>::ZERO);
200 }
201
202 #[test]
203 fn one() {
204 assert_eq!(crate::p8::round_from(1.0f64), crate::p8::ONE);
205 assert_eq!(crate::p16::round_from(1.0f64), crate::p16::ONE);
206 assert_eq!(crate::p32::round_from(1.0f64), crate::p32::ONE);
207 assert_eq!(crate::p64::round_from(1.0f64), crate::p64::ONE);
208 assert_eq!(Posit::<8, 0, i8>::round_from(1.0f64), Posit::<8, 0, i8>::ONE);
209 assert_eq!(Posit::<10, 0, i16>::round_from(1.0f64), Posit::<10, 0, i16>::ONE);
210 assert_eq!(Posit::<10, 1, i16>::round_from(1.0f64), Posit::<10, 1, i16>::ONE);
211 assert_eq!(Posit::<10, 2, i16>::round_from(1.0f64), Posit::<10, 2, i16>::ONE);
212 assert_eq!(Posit::<10, 3, i16>::round_from(1.0f64), Posit::<10, 3, i16>::ONE);
213 }
214
215 #[test]
216 fn minus_one() {
217 assert_eq!(crate::p8::round_from(-1.0f64), crate::p8::MINUS_ONE);
218 assert_eq!(crate::p16::round_from(-1.0f64), crate::p16::MINUS_ONE);
219 assert_eq!(crate::p32::round_from(-1.0f64), crate::p32::MINUS_ONE);
220 assert_eq!(crate::p64::round_from(-1.0f64), crate::p64::MINUS_ONE);
221 assert_eq!(Posit::<8, 0, i8>::round_from(-1.0f64), Posit::<8, 0, i8>::MINUS_ONE);
222 assert_eq!(Posit::<10, 0, i16>::round_from(-1.0f64), Posit::<10, 0, i16>::MINUS_ONE);
223 assert_eq!(Posit::<10, 1, i16>::round_from(-1.0f64), Posit::<10, 1, i16>::MINUS_ONE);
224 assert_eq!(Posit::<10, 2, i16>::round_from(-1.0f64), Posit::<10, 2, i16>::MINUS_ONE);
225 assert_eq!(Posit::<10, 3, i16>::round_from(-1.0f64), Posit::<10, 3, i16>::MINUS_ONE);
226 }
227
228 #[test]
229 fn nan() {
230 assert_eq!(crate::p8::round_from(f64::NAN), crate::p8::NAR);
231 assert_eq!(crate::p16::round_from(f64::NAN), crate::p16::NAR);
232 assert_eq!(crate::p32::round_from(f64::NAN), crate::p32::NAR);
233 assert_eq!(crate::p64::round_from(f64::NAN), crate::p64::NAR);
234 assert_eq!(Posit::<8, 0, i8>::round_from(f64::NAN), Posit::<8, 0, i8>::NAR);
235 assert_eq!(Posit::<10, 0, i16>::round_from(f64::NAN), Posit::<10, 0, i16>::NAR);
236 assert_eq!(Posit::<10, 1, i16>::round_from(f64::NAN), Posit::<10, 1, i16>::NAR);
237 assert_eq!(Posit::<10, 2, i16>::round_from(f64::NAN), Posit::<10, 2, i16>::NAR);
238 assert_eq!(Posit::<10, 3, i16>::round_from(f64::NAN), Posit::<10, 3, i16>::NAR);
239 }
240
241 #[test]
242 fn min_positive() {
243 assert_eq!(crate::p8::round_from(f64::MIN_POSITIVE), crate::p8::MIN_POSITIVE);
244 assert_eq!(crate::p16::round_from(f64::MIN_POSITIVE), crate::p16::MIN_POSITIVE);
245 assert_eq!(crate::p32::round_from(f64::MIN_POSITIVE), crate::p32::MIN_POSITIVE);
246 assert_eq!(crate::p64::round_from(f64::MIN_POSITIVE), crate::p64::MIN_POSITIVE);
247 assert_eq!(Posit::<8, 0, i8>::round_from(f64::MIN_POSITIVE), Posit::<8, 0, i8>::MIN_POSITIVE);
248 assert_eq!(Posit::<10, 0, i16>::round_from(f64::MIN_POSITIVE), Posit::<10, 0, i16>::MIN_POSITIVE);
249 assert_eq!(Posit::<10, 1, i16>::round_from(f64::MIN_POSITIVE), Posit::<10, 1, i16>::MIN_POSITIVE);
250 assert_eq!(Posit::<10, 2, i16>::round_from(f64::MIN_POSITIVE), Posit::<10, 2, i16>::MIN_POSITIVE);
251 assert_eq!(Posit::<10, 3, i16>::round_from(f64::MIN_POSITIVE), Posit::<10, 3, i16>::MIN_POSITIVE);
252 }
253
254 #[test]
255 fn max_negative() {
256 assert_eq!(crate::p8::round_from(-f64::MIN_POSITIVE), crate::p8::MAX_NEGATIVE);
257 assert_eq!(crate::p16::round_from(-f64::MIN_POSITIVE), crate::p16::MAX_NEGATIVE);
258 assert_eq!(crate::p32::round_from(-f64::MIN_POSITIVE), crate::p32::MAX_NEGATIVE);
259 assert_eq!(crate::p64::round_from(-f64::MIN_POSITIVE), crate::p64::MAX_NEGATIVE);
260 assert_eq!(Posit::<8, 0, i8>::round_from(-f64::MIN_POSITIVE), Posit::<8, 0, i8>::MAX_NEGATIVE);
261 assert_eq!(Posit::<10, 0, i16>::round_from(-f64::MIN_POSITIVE), Posit::<10, 0, i16>::MAX_NEGATIVE);
262 assert_eq!(Posit::<10, 1, i16>::round_from(-f64::MIN_POSITIVE), Posit::<10, 1, i16>::MAX_NEGATIVE);
263 assert_eq!(Posit::<10, 2, i16>::round_from(-f64::MIN_POSITIVE), Posit::<10, 2, i16>::MAX_NEGATIVE);
264 assert_eq!(Posit::<10, 3, i16>::round_from(-f64::MIN_POSITIVE), Posit::<10, 3, i16>::MAX_NEGATIVE);
265 }
266
267 const PROPTEST_CASES: u32 = if cfg!(debug_assertions) {0x1_0000} else {0x80_0000};
268 proptest!{
269 #![proptest_config(ProptestConfig::with_cases(PROPTEST_CASES))]
270
271 #[test]
272 fn posit_10_0_proptest(float in any::<f64>()) {
273 assert!(is_correct_rounded::<10, 0, i16>(float), "{:?}", float)
274 }
275
276 #[test]
277 fn posit_10_1_proptest(float in any::<f64>()) {
278 assert!(is_correct_rounded::<10, 1, i16>(float), "{:?}", float)
279 }
280
281 #[test]
282 fn posit_10_2_proptest(float in any::<f64>()) {
283 assert!(is_correct_rounded::<10, 2, i16>(float), "{:?}", float)
284 }
285
286 #[test]
287 fn posit_10_3_proptest(float in any::<f64>()) {
288 assert!(is_correct_rounded::<10, 3, i16>(float), "{:?}", float)
289 }
290
291 #[test]
292 fn posit_8_0_proptest(float in any::<f64>()) {
293 assert!(is_correct_rounded::<8, 0, i8>(float), "{:?}", float)
294 }
295
296 #[test]
297 fn p8_proptest(float in any::<f64>()) {
298 assert!(is_correct_rounded::<8, 2, i8>(float), "{:?}", float)
299 }
300
301 #[test]
302 fn p16_proptest(float in any::<f64>()) {
303 assert!(is_correct_rounded::<16, 2, i16>(float), "{:?}", float)
304 }
305
306 #[test]
307 fn p32_proptest(float in any::<f64>()) {
308 assert!(is_correct_rounded::<32, 2, i32>(float), "{:?}", float)
309 }
310
311 #[test]
312 fn p64_proptest(float in any::<f64>()) {
313 assert!(is_correct_rounded::<64, 2, i64>(float), "{:?}", float)
314 }
315 }
316 }
317
318 mod f32 {
319 use super::*;
320
321 fn is_correct_rounded<const N: u32, const ES: u32, Int: crate::Int>(float: f32) -> bool
323 where
324 Rational: From<Decoded<N, ES, Int>> + TryFrom<Posit<N, ES, Int>> + TryFrom<f32>,
325 <Rational as TryFrom<Posit<N, ES, Int>>>::Error: core::fmt::Debug
326 {
327 let posit = Posit::<N, ES, Int>::round_from(float);
328 match Rational::try_from(float) {
329 Ok(exact) => super::rational::is_correct_rounded(exact, posit),
330 Err(_) => posit == Posit::NAR,
331 }
332 }
333
334 #[test]
335 fn zero() {
336 assert_eq!(crate::p8::round_from(0.0f32), crate::p8::ZERO);
337 assert_eq!(crate::p16::round_from(0.0f32), crate::p16::ZERO);
338 assert_eq!(crate::p32::round_from(0.0f32), crate::p32::ZERO);
339 assert_eq!(crate::p64::round_from(0.0f32), crate::p64::ZERO);
340 assert_eq!(Posit::<8, 0, i8>::round_from(0.0f32), Posit::<8, 0, i8>::ZERO);
341 assert_eq!(Posit::<10, 0, i16>::round_from(0.0f32), Posit::<10, 0, i16>::ZERO);
342 assert_eq!(Posit::<10, 1, i16>::round_from(0.0f32), Posit::<10, 1, i16>::ZERO);
343 assert_eq!(Posit::<10, 2, i16>::round_from(0.0f32), Posit::<10, 2, i16>::ZERO);
344 assert_eq!(Posit::<10, 3, i16>::round_from(0.0f32), Posit::<10, 3, i16>::ZERO);
345 }
346
347 #[test]
348 fn one() {
349 assert_eq!(crate::p8::round_from(1.0f32), crate::p8::ONE);
350 assert_eq!(crate::p16::round_from(1.0f32), crate::p16::ONE);
351 assert_eq!(crate::p32::round_from(1.0f32), crate::p32::ONE);
352 assert_eq!(crate::p64::round_from(1.0f32), crate::p64::ONE);
353 assert_eq!(Posit::<8, 0, i8>::round_from(1.0f32), Posit::<8, 0, i8>::ONE);
354 assert_eq!(Posit::<10, 0, i16>::round_from(1.0f32), Posit::<10, 0, i16>::ONE);
355 assert_eq!(Posit::<10, 1, i16>::round_from(1.0f32), Posit::<10, 1, i16>::ONE);
356 assert_eq!(Posit::<10, 2, i16>::round_from(1.0f32), Posit::<10, 2, i16>::ONE);
357 assert_eq!(Posit::<10, 3, i16>::round_from(1.0f32), Posit::<10, 3, i16>::ONE);
358 }
359
360 #[test]
361 fn minus_one() {
362 assert_eq!(crate::p8::round_from(-1.0f32), crate::p8::MINUS_ONE);
363 assert_eq!(crate::p16::round_from(-1.0f32), crate::p16::MINUS_ONE);
364 assert_eq!(crate::p32::round_from(-1.0f32), crate::p32::MINUS_ONE);
365 assert_eq!(crate::p64::round_from(-1.0f32), crate::p64::MINUS_ONE);
366 assert_eq!(Posit::<8, 0, i8>::round_from(-1.0f32), Posit::<8, 0, i8>::MINUS_ONE);
367 assert_eq!(Posit::<10, 0, i16>::round_from(-1.0f32), Posit::<10, 0, i16>::MINUS_ONE);
368 assert_eq!(Posit::<10, 1, i16>::round_from(-1.0f32), Posit::<10, 1, i16>::MINUS_ONE);
369 assert_eq!(Posit::<10, 2, i16>::round_from(-1.0f32), Posit::<10, 2, i16>::MINUS_ONE);
370 assert_eq!(Posit::<10, 3, i16>::round_from(-1.0f32), Posit::<10, 3, i16>::MINUS_ONE);
371 }
372
373 #[test]
374 fn nan() {
375 assert_eq!(crate::p8::round_from(f32::NAN), crate::p8::NAR);
376 assert_eq!(crate::p16::round_from(f32::NAN), crate::p16::NAR);
377 assert_eq!(crate::p32::round_from(f32::NAN), crate::p32::NAR);
378 assert_eq!(crate::p64::round_from(f32::NAN), crate::p64::NAR);
379 assert_eq!(Posit::<8, 0, i8>::round_from(f32::NAN), Posit::<8, 0, i8>::NAR);
380 assert_eq!(Posit::<10, 0, i16>::round_from(f32::NAN), Posit::<10, 0, i16>::NAR);
381 assert_eq!(Posit::<10, 1, i16>::round_from(f32::NAN), Posit::<10, 1, i16>::NAR);
382 assert_eq!(Posit::<10, 2, i16>::round_from(f32::NAN), Posit::<10, 2, i16>::NAR);
383 assert_eq!(Posit::<10, 3, i16>::round_from(f32::NAN), Posit::<10, 3, i16>::NAR);
384 }
385
386 #[test]
387 fn min_positive() {
388 assert_eq!(crate::p8::round_from(f32::MIN_POSITIVE), crate::p8::MIN_POSITIVE);
389 assert_eq!(crate::p16::round_from(f32::MIN_POSITIVE), crate::p16::MIN_POSITIVE);
390 assert_eq!(crate::p32::round_from(f32::MIN_POSITIVE), crate::p32::MIN_POSITIVE);
391 assert_eq!(Posit::<8, 0, i8>::round_from(f32::MIN_POSITIVE), Posit::<8, 0, i8>::MIN_POSITIVE);
393 assert_eq!(Posit::<10, 0, i16>::round_from(f32::MIN_POSITIVE), Posit::<10, 0, i16>::MIN_POSITIVE);
394 assert_eq!(Posit::<10, 1, i16>::round_from(f32::MIN_POSITIVE), Posit::<10, 1, i16>::MIN_POSITIVE);
395 assert_eq!(Posit::<10, 2, i16>::round_from(f32::MIN_POSITIVE), Posit::<10, 2, i16>::MIN_POSITIVE);
396 assert_eq!(Posit::<10, 3, i16>::round_from(f32::MIN_POSITIVE), Posit::<10, 3, i16>::MIN_POSITIVE);
397 }
398
399 #[test]
400 fn max_negative() {
401 assert_eq!(crate::p8::round_from(-f32::MIN_POSITIVE), crate::p8::MAX_NEGATIVE);
402 assert_eq!(crate::p16::round_from(-f32::MIN_POSITIVE), crate::p16::MAX_NEGATIVE);
403 assert_eq!(crate::p32::round_from(-f32::MIN_POSITIVE), crate::p32::MAX_NEGATIVE);
404 assert_eq!(Posit::<8, 0, i8>::round_from(-f32::MIN_POSITIVE), Posit::<8, 0, i8>::MAX_NEGATIVE);
406 assert_eq!(Posit::<10, 0, i16>::round_from(-f32::MIN_POSITIVE), Posit::<10, 0, i16>::MAX_NEGATIVE);
407 assert_eq!(Posit::<10, 1, i16>::round_from(-f32::MIN_POSITIVE), Posit::<10, 1, i16>::MAX_NEGATIVE);
408 assert_eq!(Posit::<10, 2, i16>::round_from(-f32::MIN_POSITIVE), Posit::<10, 2, i16>::MAX_NEGATIVE);
409 assert_eq!(Posit::<10, 3, i16>::round_from(-f32::MIN_POSITIVE), Posit::<10, 3, i16>::MAX_NEGATIVE);
410 }
411
412 const PROPTEST_CASES: u32 = if cfg!(debug_assertions) {0x1_0000} else {0x80_0000};
413 proptest!{
414 #![proptest_config(ProptestConfig::with_cases(PROPTEST_CASES))]
415
416 #[test]
417 fn posit_10_0_proptest(float in any::<f32>()) {
418 assert!(is_correct_rounded::<10, 0, i16>(float), "{:?}", float)
419 }
420
421 #[test]
422 fn posit_10_1_proptest(float in any::<f32>()) {
423 assert!(is_correct_rounded::<10, 1, i16>(float), "{:?}", float)
424 }
425
426 #[test]
427 fn posit_10_2_proptest(float in any::<f32>()) {
428 assert!(is_correct_rounded::<10, 2, i16>(float), "{:?}", float)
429 }
430
431 #[test]
432 fn posit_10_3_proptest(float in any::<f32>()) {
433 assert!(is_correct_rounded::<10, 3, i16>(float), "{:?}", float)
434 }
435
436 #[test]
437 fn posit_8_0_proptest(float in any::<f32>()) {
438 assert!(is_correct_rounded::<8, 0, i8>(float), "{:?}", float)
439 }
440
441 #[test]
442 fn p8_proptest(float in any::<f32>()) {
443 assert!(is_correct_rounded::<8, 2, i8>(float), "{:?}", float)
444 }
445
446 #[test]
447 fn p16_proptest(float in any::<f32>()) {
448 assert!(is_correct_rounded::<16, 2, i16>(float), "{:?}", float)
449 }
450
451 #[test]
452 fn p32_proptest(float in any::<f32>()) {
453 assert!(is_correct_rounded::<32, 2, i32>(float), "{:?}", float)
454 }
455
456 #[test]
457 fn p64_proptest(float in any::<f32>()) {
458 assert!(is_correct_rounded::<64, 2, i64>(float), "{:?}", float)
459 }
460 }
461 }
462
463 }