malachite_float/conversion/
primitive_int_from_float.rs

1// Copyright © 2025 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::InnerFloat::{Finite, Infinity, NaN, Zero};
10use crate::arithmetic::is_power_of_2::float_is_signed_min;
11use crate::{Float, significand_bits};
12use core::cmp::Ordering::{self, *};
13use malachite_base::num::arithmetic::traits::{DivisibleByPowerOf2, ShrRound};
14use malachite_base::num::basic::signeds::PrimitiveSigned;
15use malachite_base::num::basic::unsigneds::PrimitiveUnsigned;
16use malachite_base::num::conversion::from::{SignedFromFloatError, UnsignedFromFloatError};
17use malachite_base::num::conversion::traits::{ConvertibleFrom, RoundingFrom, WrappingFrom};
18use malachite_base::rounding_modes::RoundingMode::{self, *};
19use malachite_nz::integer::Integer;
20use malachite_nz::natural::Natural;
21
22#[allow(clippy::type_repetition_in_bounds)]
23fn unsigned_rounding_from_float<T: PrimitiveUnsigned>(f: Float, rm: RoundingMode) -> (T, Ordering)
24where
25    for<'a> T: TryFrom<&'a Natural>,
26{
27    match f {
28        float_nan!() => panic!("Can't convert NaN to {}", T::NAME),
29        float_infinity!() => match rm {
30            Floor | Down | Nearest => (T::MAX, Less),
31            _ => panic!("Can't convert Infinity to {} using {}", T::NAME, rm),
32        },
33        float_negative_infinity!() => match rm {
34            Ceiling | Down | Nearest => (T::ZERO, Greater),
35            _ => panic!("Can't convert -Infinity to {} using {}", T::NAME, rm),
36        },
37        float_either_zero!() => (T::ZERO, Equal),
38        Float(Finite {
39            sign,
40            exponent,
41            significand,
42            ..
43        }) => {
44            let exponent = i64::from(exponent);
45            if !sign {
46                match rm {
47                    Ceiling | Down | Nearest => (T::ZERO, Greater),
48                    _ => panic!("Cannot convert negative Float to {} using {}", T::NAME, rm),
49                }
50            } else if exponent < 0 {
51                match rm {
52                    Floor | Down | Nearest => (T::ZERO, Less),
53                    Ceiling | Up => (T::ONE, Greater),
54                    Exact => {
55                        panic!("Cannot convert Float to {} using {}", T::NAME, rm)
56                    }
57                }
58            } else if exponent > i64::wrapping_from(T::WIDTH) {
59                match rm {
60                    Floor | Down | Nearest => (T::MAX, Less),
61                    _ => panic!("Cannot convert large Float to {} using {}", T::NAME, rm),
62                }
63            } else {
64                let sb = significand_bits(&significand);
65                let eb = exponent.unsigned_abs();
66                let (n, o) = if sb >= eb {
67                    significand.shr_round(sb - eb, rm)
68                } else {
69                    (significand << (eb - sb), Equal)
70                };
71                let (n, o) = if let Ok(n) = T::try_from(&n) {
72                    (n, o)
73                } else {
74                    match rm {
75                        Floor | Down | Nearest => (T::MAX, Less),
76                        _ => panic!("Cannot convert large Float to {} using {}", T::NAME, rm),
77                    }
78                };
79                (n, o)
80            }
81        }
82    }
83}
84
85#[allow(clippy::type_repetition_in_bounds)]
86fn unsigned_rounding_from_float_ref<T: PrimitiveUnsigned>(
87    f: &Float,
88    rm: RoundingMode,
89) -> (T, Ordering)
90where
91    for<'a> T: TryFrom<&'a Natural>,
92{
93    match f {
94        float_nan!() => panic!("Can't convert NaN to {}", T::NAME),
95        float_infinity!() => match rm {
96            Floor | Down | Nearest => (T::MAX, Less),
97            _ => panic!("Can't convert Infinity to {} using {}", T::NAME, rm),
98        },
99        float_negative_infinity!() => match rm {
100            Ceiling | Down | Nearest => (T::ZERO, Greater),
101            _ => panic!("Can't convert -Infinity to {} using {}", T::NAME, rm),
102        },
103        float_either_zero!() => (T::ZERO, Equal),
104        Float(Finite {
105            sign,
106            exponent,
107            significand,
108            ..
109        }) => {
110            let exponent = i64::from(*exponent);
111            if !sign {
112                match rm {
113                    Ceiling | Down | Nearest => (T::ZERO, Greater),
114                    _ => panic!("Cannot convert negative Float to {} using {}", T::NAME, rm),
115                }
116            } else if exponent < 0 {
117                match rm {
118                    Floor | Down | Nearest => (T::ZERO, Less),
119                    Ceiling | Up => (T::ONE, Greater),
120                    Exact => {
121                        panic!("Cannot convert Float to {} using {}", T::NAME, rm)
122                    }
123                }
124            } else if exponent > i64::wrapping_from(T::WIDTH) {
125                match rm {
126                    Floor | Down | Nearest => (T::MAX, Less),
127                    _ => panic!("Cannot convert large Float to {} using {}", T::NAME, rm),
128                }
129            } else {
130                let sb = significand_bits(significand);
131                let eb = exponent.unsigned_abs();
132                let (n, o) = if sb >= eb {
133                    significand.shr_round(sb - eb, rm)
134                } else {
135                    (significand << (eb - sb), Equal)
136                };
137                let (n, o) = if let Ok(n) = T::try_from(&n) {
138                    (n, o)
139                } else {
140                    match rm {
141                        Floor | Down | Nearest => (T::MAX, Less),
142                        _ => panic!("Cannot convert large Float to {} using {}", T::NAME, rm),
143                    }
144                };
145                (n, o)
146            }
147        }
148    }
149}
150
151#[allow(clippy::type_repetition_in_bounds)]
152fn unsigned_try_from_float<T: PrimitiveUnsigned>(f: Float) -> Result<T, UnsignedFromFloatError>
153where
154    for<'a> T: WrappingFrom<&'a Natural>,
155{
156    match f {
157        float_either_zero!() => Ok(T::ZERO),
158        Float(Finite {
159            sign,
160            exponent,
161            significand,
162            ..
163        }) => {
164            let exponent = i64::from(exponent);
165            if !sign {
166                Err(UnsignedFromFloatError::FloatNegative)
167            } else if exponent <= 0 || exponent > i64::wrapping_from(T::WIDTH) {
168                Err(UnsignedFromFloatError::FloatNonIntegerOrOutOfRange)
169            } else {
170                let sb = significand_bits(&significand);
171                let eb = exponent.unsigned_abs();
172                let n = if sb >= eb {
173                    let bits = sb - eb;
174                    if significand.divisible_by_power_of_2(bits) {
175                        Ok(significand >> bits)
176                    } else {
177                        Err(UnsignedFromFloatError::FloatNonIntegerOrOutOfRange)
178                    }
179                } else {
180                    Ok(significand << (eb - sb))
181                };
182                n.map(|n| T::wrapping_from(&n))
183            }
184        }
185        _ => Err(UnsignedFromFloatError::FloatInfiniteOrNan),
186    }
187}
188
189#[allow(clippy::type_repetition_in_bounds)]
190fn unsigned_try_from_float_ref<T: PrimitiveUnsigned>(f: &Float) -> Result<T, UnsignedFromFloatError>
191where
192    for<'a> T: WrappingFrom<&'a Natural>,
193{
194    match f {
195        float_either_zero!() => Ok(T::ZERO),
196        Float(Finite {
197            sign,
198            exponent,
199            significand,
200            ..
201        }) => {
202            let exponent = i64::from(*exponent);
203            if !sign {
204                Err(UnsignedFromFloatError::FloatNegative)
205            } else if exponent <= 0 || exponent > i64::wrapping_from(T::WIDTH) {
206                Err(UnsignedFromFloatError::FloatNonIntegerOrOutOfRange)
207            } else {
208                let sb = significand_bits(significand);
209                let eb = exponent.unsigned_abs();
210                let n = if sb >= eb {
211                    let bits = sb - eb;
212                    if significand.divisible_by_power_of_2(bits) {
213                        Ok(significand >> bits)
214                    } else {
215                        Err(UnsignedFromFloatError::FloatNonIntegerOrOutOfRange)
216                    }
217                } else {
218                    Ok(significand << (eb - sb))
219                };
220                n.map(|n| T::wrapping_from(&n))
221            }
222        }
223        _ => Err(UnsignedFromFloatError::FloatInfiniteOrNan),
224    }
225}
226
227fn unsigned_convertible_from_float<T: PrimitiveUnsigned>(f: &Float) -> bool {
228    match f {
229        float_either_zero!() => true,
230        Float(Finite {
231            sign,
232            exponent,
233            significand,
234            ..
235        }) => {
236            let exponent = i64::from(*exponent);
237            *sign && exponent > 0 && exponent <= i64::wrapping_from(T::WIDTH) && {
238                let sb = significand_bits(significand);
239                let eb = exponent.unsigned_abs();
240                sb < eb || significand.divisible_by_power_of_2(sb - eb)
241            }
242        }
243        _ => false,
244    }
245}
246
247macro_rules! impl_unsigned_from {
248    ($t: ident) => {
249        impl RoundingFrom<Float> for $t {
250            /// Converts a [`Float`] to an unsigned primitive integer, using a specified
251            /// [`RoundingMode`] and taking the [`Float`] by value. An [`Ordering`] is also
252            /// returned, indicating whether the returned value is less than, equal to, or greater
253            /// than the original value.
254            ///
255            /// If the [`Float`] is negative (including $-\infty$), then it will be rounded to zero
256            /// when the [`RoundingMode`] is `Ceiling`, `Down`, or `Nearest`. Otherwise, this
257            /// function will panic.
258            ///
259            /// If the [`Float`] is greater than the maximum representable value of the unsigned
260            /// type (including $\infty$), then it will be rounded to the maximum value when the
261            /// [`RoundingMode`] is `Floor`, `Down`, or `Nearest`. Otherwise, this function will
262            /// panic.
263            ///
264            /// If the [`Float`] is NaN, the function will panic regardless of the rounding mode.
265            ///
266            /// # Worst-case complexity
267            /// Constant time and additional memory.
268            ///
269            /// # Panics
270            /// Panics if the [`Float`] is not an integer and `rm` is `Exact`, or if the [`Float`]
271            /// is less than zero and `rm` is not `Down`, `Ceiling`, or `Nearest`, if the [`Float`]
272            /// is greater than the maximum representable value of the unsigned type and `rm` is not
273            /// `Down`, `Floor`, or `Nearest`, or if the [`Float`] is NaN.
274            ///
275            /// # Examples
276            /// See [here](super::primitive_int_from_float#rounding_from).
277            #[inline]
278            fn rounding_from(f: Float, rm: RoundingMode) -> ($t, Ordering) {
279                unsigned_rounding_from_float(f, rm)
280            }
281        }
282
283        impl RoundingFrom<&Float> for $t {
284            /// Converts a [`Float`] to an unsigned primitive integer, using a specified
285            /// [`RoundingMode`] and taking the [`Float`] by reference. An [`Ordering`] is also
286            /// returned, indicating whether the returned value is less than, equal to, or greater
287            /// than the original value.
288            ///
289            /// If the [`Float`] is negative (including $-\infty$), then it will be rounded to zero
290            /// when the [`RoundingMode`] is `Ceiling`, `Down`, or `Nearest`. Otherwise, this
291            /// function will panic.
292            ///
293            /// If the [`Float`] is greater than the maximum representable value of the unsigned
294            /// type (including $\infty$), then it will be rounded to the maximum value when the
295            /// [`RoundingMode`] is `Floor`, `Down`, or `Nearest`. Otherwise, this function will
296            /// panic.
297            ///
298            /// If the [`Float`] is NaN, the function will panic regardless of the rounding mode.
299            ///
300            /// # Worst-case complexity
301            /// Constant time and additional memory.
302            ///
303            /// # Panics
304            /// Panics if the [`Float`] is not an integer and `rm` is `Exact`, or if the [`Float`]
305            /// is less than zero and `rm` is not `Down`, `Ceiling`, or `Nearest`, if the [`Float`]
306            /// is greater than the maximum representable value of the unsigned type and `rm` is not
307            /// `Down`, `Floor`, or `Nearest`, or if the [`Float`] is NaN.
308            ///
309            /// # Examples
310            /// See [here](super::primitive_int_from_float#rounding_from).
311            #[inline]
312            fn rounding_from(f: &Float, rm: RoundingMode) -> ($t, Ordering) {
313                unsigned_rounding_from_float_ref(f, rm)
314            }
315        }
316
317        impl TryFrom<Float> for $t {
318            type Error = UnsignedFromFloatError;
319
320            /// Converts a [`Float`] to a primitive unsigned integer, taking the [`Float`] by value.
321            /// If the [`Float`] is not equal to an unsigned primitive integer of the given type, an
322            /// error is returned.
323            ///
324            /// Both positive and negative zero convert to a primitive unsigned integer zero.
325            ///
326            /// # Worst-case complexity
327            /// Constant time and additional memory.
328            ///
329            /// # Examples
330            /// See [here](super::primitive_int_from_float#try_from).
331            #[inline]
332            fn try_from(f: Float) -> Result<$t, Self::Error> {
333                unsigned_try_from_float(f)
334            }
335        }
336
337        impl TryFrom<&Float> for $t {
338            type Error = UnsignedFromFloatError;
339
340            /// Converts a [`Float`] to a primitive unsigned integer, taking the [`Float`] by
341            /// reference. If the [`Float`] is not equal to an unsigned primitive integer of the
342            /// given type, an error is returned.
343            ///
344            /// Both positive and negative zero convert to a primitive unsigned integer zero.
345            ///
346            /// # Worst-case complexity
347            /// Constant time and additional memory.
348            ///
349            /// # Examples
350            /// See [here](super::primitive_int_from_float#try_from).
351            #[inline]
352            fn try_from(f: &Float) -> Result<$t, Self::Error> {
353                unsigned_try_from_float_ref(f)
354            }
355        }
356
357        impl ConvertibleFrom<&Float> for $t {
358            /// Determines whether a [`Float`] can be converted to an unsigned primitive integer,
359            /// taking the [`Float`] by reference.
360            ///
361            /// Both positive and negative zero are convertible to any unsigned primitive integer.
362            /// (Although negative zero is nominally negative, the real number it represents is
363            /// zero, which is not negative.)
364            ///
365            /// # Worst-case complexity
366            /// Constant time and additional memory.
367            ///
368            /// # Examples
369            /// See [here](super::primitive_int_from_float#convertible_from).
370            #[inline]
371            fn convertible_from(f: &Float) -> bool {
372                unsigned_convertible_from_float::<$t>(f)
373            }
374        }
375    };
376}
377apply_to_unsigneds!(impl_unsigned_from);
378
379#[allow(clippy::trait_duplication_in_bounds, clippy::type_repetition_in_bounds)]
380fn signed_rounding_from_float<T: PrimitiveSigned>(f: Float, rm: RoundingMode) -> (T, Ordering)
381where
382    for<'a> T: TryFrom<&'a Natural> + TryFrom<&'a Integer>,
383{
384    match f {
385        float_nan!() => panic!("Can't convert NaN to {}", T::NAME),
386        float_infinity!() => match rm {
387            Floor | Down | Nearest => (T::MAX, Less),
388            _ => panic!("Can't convert Infinity to {} using {}", T::NAME, rm),
389        },
390        float_negative_infinity!() => match rm {
391            Ceiling | Down | Nearest => (T::MIN, Greater),
392            _ => panic!("Can't convert -Infinity to {} using {}", T::NAME, rm),
393        },
394        float_either_zero!() => (T::ZERO, Equal),
395        Float(Finite {
396            sign,
397            exponent,
398            significand,
399            ..
400        }) => {
401            let exponent = i64::from(exponent);
402            if sign {
403                if exponent < 0 {
404                    match rm {
405                        Floor | Down | Nearest => (T::ZERO, Less),
406                        Ceiling | Up => (T::ONE, Greater),
407                        Exact => {
408                            panic!("Cannot convert Float to Integer using {rm}")
409                        }
410                    }
411                } else if exponent >= i64::wrapping_from(T::WIDTH) {
412                    match rm {
413                        Floor | Down | Nearest => (T::MAX, Less),
414                        _ => {
415                            panic!("Cannot convert Float to Integer using {rm}")
416                        }
417                    }
418                } else {
419                    let sb = significand_bits(&significand);
420                    let eb = exponent.unsigned_abs();
421                    let (n, o) = if sb >= eb {
422                        significand.shr_round(sb - eb, rm)
423                    } else {
424                        (significand << (eb - sb), Equal)
425                    };
426                    let (n, o) = if let Ok(n) = T::try_from(&n) {
427                        (n, o)
428                    } else {
429                        match rm {
430                            Floor | Down | Nearest => (T::MAX, Less),
431                            _ => {
432                                panic!("Cannot convert large Float to {} using {}", T::NAME, rm)
433                            }
434                        }
435                    };
436                    (n, o)
437                }
438            } else if exponent < 0 {
439                match rm {
440                    Ceiling | Down | Nearest => (T::ZERO, Greater),
441                    Floor | Up => (T::NEGATIVE_ONE, Less),
442                    Exact => {
443                        panic!("Cannot convert Float to Integer using {rm}")
444                    }
445                }
446            } else if exponent > i64::wrapping_from(T::WIDTH) {
447                // This doesn't catch the case where -2^(W+1) < x < -2^W, but that's ok because the
448                // next else block handles it.
449                match rm {
450                    Ceiling | Down | Nearest => (T::MIN, Greater),
451                    _ => {
452                        panic!("Cannot convert Float to Integer using {rm}")
453                    }
454                }
455            } else {
456                let sb = significand_bits(&significand);
457                let eb = exponent.unsigned_abs();
458                let (n, o) = if sb >= eb {
459                    significand.shr_round(sb - eb, -rm)
460                } else {
461                    (significand << (eb - sb), Equal)
462                };
463                let (n, o) = if let Ok(n) = T::try_from(&-n) {
464                    (n, o.reverse())
465                } else {
466                    match rm {
467                        Ceiling | Down | Nearest => (T::MIN, Greater),
468                        _ => panic!(
469                            "Cannot convert large negative Float to {} using {}",
470                            T::NAME,
471                            rm
472                        ),
473                    }
474                };
475                (n, o)
476            }
477        }
478    }
479}
480
481#[allow(clippy::trait_duplication_in_bounds, clippy::type_repetition_in_bounds)]
482fn signed_rounding_from_float_ref<T: PrimitiveSigned>(f: &Float, rm: RoundingMode) -> (T, Ordering)
483where
484    for<'a> T: TryFrom<&'a Natural> + TryFrom<&'a Integer>,
485{
486    match f {
487        float_nan!() => panic!("Can't convert NaN to {}", T::NAME),
488        float_infinity!() => match rm {
489            Floor | Down | Nearest => (T::MAX, Less),
490            _ => panic!("Can't convert Infinity to {} using {}", T::NAME, rm),
491        },
492        float_negative_infinity!() => match rm {
493            Ceiling | Down | Nearest => (T::MIN, Greater),
494            _ => panic!("Can't convert -Infinity to {} using {}", T::NAME, rm),
495        },
496        float_either_zero!() => (T::ZERO, Equal),
497        Float(Finite {
498            sign,
499            exponent,
500            significand,
501            ..
502        }) => {
503            let exponent = i64::from(*exponent);
504            if *sign {
505                if exponent < 0 {
506                    match rm {
507                        Floor | Down | Nearest => (T::ZERO, Less),
508                        Ceiling | Up => (T::ONE, Greater),
509                        Exact => {
510                            panic!("Cannot convert Float to Integer using {rm}")
511                        }
512                    }
513                } else if exponent >= i64::wrapping_from(T::WIDTH) {
514                    match rm {
515                        Floor | Down | Nearest => (T::MAX, Less),
516                        _ => {
517                            panic!("Cannot convert Float to Integer using {rm}")
518                        }
519                    }
520                } else {
521                    let sb = significand_bits(significand);
522                    let eb = exponent.unsigned_abs();
523                    let (n, o) = if sb >= eb {
524                        significand.shr_round(sb - eb, rm)
525                    } else {
526                        (significand << (eb - sb), Equal)
527                    };
528                    let (n, o) = if let Ok(n) = T::try_from(&n) {
529                        (n, o)
530                    } else {
531                        match rm {
532                            Floor | Down | Nearest => (T::MAX, Less),
533                            _ => {
534                                panic!("Cannot convert large Float to {} using {}", T::NAME, rm)
535                            }
536                        }
537                    };
538                    (n, o)
539                }
540            } else if exponent < 0 {
541                match rm {
542                    Ceiling | Down | Nearest => (T::ZERO, Greater),
543                    Floor | Up => (T::NEGATIVE_ONE, Less),
544                    Exact => {
545                        panic!("Cannot convert Float to Integer using {rm}")
546                    }
547                }
548            } else if exponent > i64::wrapping_from(T::WIDTH) {
549                // This doesn't catch the case where -2^(W+1) < x < -2^W, but that's ok because the
550                // next else block handles it.
551                match rm {
552                    Ceiling | Down | Nearest => (T::MIN, Greater),
553                    _ => {
554                        panic!("Cannot convert Float to Integer using {rm}")
555                    }
556                }
557            } else {
558                let sb = significand_bits(significand);
559                let eb = exponent.unsigned_abs();
560                let (n, o) = if sb >= eb {
561                    significand.shr_round(sb - eb, -rm)
562                } else {
563                    (significand << (eb - sb), Equal)
564                };
565                let (n, o) = if let Ok(n) = T::try_from(&-n) {
566                    (n, o.reverse())
567                } else {
568                    match rm {
569                        Ceiling | Down | Nearest => (T::MIN, Greater),
570                        _ => panic!(
571                            "Cannot convert large negative Float to {} using {}",
572                            T::NAME,
573                            rm
574                        ),
575                    }
576                };
577                (n, o)
578            }
579        }
580    }
581}
582
583#[allow(clippy::type_repetition_in_bounds)]
584fn signed_try_from_float<T: PrimitiveSigned>(f: Float) -> Result<T, SignedFromFloatError>
585where
586    for<'a> T: TryFrom<&'a Integer>,
587{
588    match f {
589        float_either_zero!() => Ok(T::ZERO),
590        Float(Finite {
591            sign,
592            exponent,
593            significand,
594            ..
595        }) => {
596            let exponent = i64::from(exponent);
597            if exponent <= 0
598                || (sign && exponent >= i64::wrapping_from(T::WIDTH)
599                    || !sign && exponent > i64::wrapping_from(T::WIDTH))
600            {
601                Err(SignedFromFloatError::FloatNonIntegerOrOutOfRange)
602            } else {
603                let sb = significand_bits(&significand);
604                let eb = exponent.unsigned_abs();
605                let i = Integer::from_sign_and_abs(
606                    sign,
607                    if sb >= eb {
608                        let bits = sb - eb;
609                        if significand.divisible_by_power_of_2(bits) {
610                            significand >> bits
611                        } else {
612                            return Err(SignedFromFloatError::FloatNonIntegerOrOutOfRange);
613                        }
614                    } else {
615                        significand << (eb - sb)
616                    },
617                );
618                T::try_from(&i).map_err(|_| SignedFromFloatError::FloatNonIntegerOrOutOfRange)
619            }
620        }
621        _ => Err(SignedFromFloatError::FloatInfiniteOrNan),
622    }
623}
624
625#[allow(clippy::type_repetition_in_bounds)]
626fn signed_try_from_float_ref<T: PrimitiveSigned>(f: &Float) -> Result<T, SignedFromFloatError>
627where
628    for<'a> T: TryFrom<&'a Integer>,
629{
630    match f {
631        float_either_zero!() => Ok(T::ZERO),
632        Float(Finite {
633            sign,
634            exponent,
635            significand,
636            ..
637        }) => {
638            let exponent = i64::from(*exponent);
639            if exponent <= 0
640                || (*sign && exponent >= i64::wrapping_from(T::WIDTH)
641                    || !*sign && exponent > i64::wrapping_from(T::WIDTH))
642            {
643                Err(SignedFromFloatError::FloatNonIntegerOrOutOfRange)
644            } else {
645                let sb = significand_bits(significand);
646                let eb = exponent.unsigned_abs();
647                let i = Integer::from_sign_and_abs(
648                    *sign,
649                    if sb >= eb {
650                        let bits = sb - eb;
651                        if significand.divisible_by_power_of_2(bits) {
652                            significand >> bits
653                        } else {
654                            return Err(SignedFromFloatError::FloatNonIntegerOrOutOfRange);
655                        }
656                    } else {
657                        significand << (eb - sb)
658                    },
659                );
660                T::try_from(&i).map_err(|_| SignedFromFloatError::FloatNonIntegerOrOutOfRange)
661            }
662        }
663        _ => Err(SignedFromFloatError::FloatInfiniteOrNan),
664    }
665}
666
667fn signed_convertible_from_float<T: PrimitiveSigned>(f: &Float) -> bool {
668    match f {
669        float_either_zero!() => true,
670        Float(Finite {
671            exponent,
672            significand,
673            ..
674        }) => {
675            let exponent = i64::from(*exponent);
676            if exponent <= 0 {
677                return false;
678            }
679            if exponent >= i64::wrapping_from(T::WIDTH) {
680                float_is_signed_min::<T>(f)
681            } else {
682                let sb = significand_bits(significand);
683                let eb = exponent.unsigned_abs();
684                sb < eb || significand.divisible_by_power_of_2(sb - eb)
685            }
686        }
687        _ => false,
688    }
689}
690
691macro_rules! impl_signed_from {
692    ($t: ident) => {
693        impl RoundingFrom<Float> for $t {
694            /// Converts a [`Float`] to a signed primitive integer, using a specified
695            /// [`RoundingMode`] and taking the [`Float`] by value. An [`Ordering`] is also
696            /// returned, indicating whether the returned value is less than, equal to, or greater
697            /// than the original value.
698            ///
699            /// If the [`Float`] is less than the minimum representable value of the signed type
700            /// (including $-\infty$), then it will be rounded to zero when the [`RoundingMode`] is
701            /// `Ceiling`, `Down`, or `Nearest`. Otherwise, this function will panic.
702            ///
703            /// If the [`Float`] is greater than the maximum representable value of the signed type
704            /// (including $\infty$), then it will be rounded to the maximum value when the
705            /// [`RoundingMode`] is `Floor`, `Down`, or `Nearest`. Otherwise, this function will
706            /// panic.
707            ///
708            /// If the [`Float`] is NaN, the function will panic regardless of the rounding mode.
709            ///
710            /// # Worst-case complexity
711            /// Constant time and additional memory.
712            ///
713            /// # Panics
714            /// Panics if the [`Float`] is not an integer and `rm` is `Exact`, or if the [`Float`]
715            /// is smaller than the minimum representable value of the signed type and `rm` is not
716            /// `Down`, `Ceiling`, or `Nearest`, if the [`Float`] is greater than the maximum
717            /// representable value of the signed type and `rm` is not `Down`, `Floor`, or
718            /// `Nearest`, or if the [`Float`] is NaN.
719            ///
720            /// # Examples
721            /// See [here](super::primitive_int_from_float#rounding_from).
722            #[inline]
723            fn rounding_from(f: Float, rm: RoundingMode) -> ($t, Ordering) {
724                signed_rounding_from_float(f, rm)
725            }
726        }
727
728        impl RoundingFrom<&Float> for $t {
729            /// Converts a [`Float`] to a signed primitive integer, using a specified
730            /// [`RoundingMode`] and taking the [`Float`] by reference. An [`Ordering`] is also
731            /// returned, indicating whether the returned value is less than, equal to, or greater
732            /// than the original value.
733            ///
734            /// If the [`Float`] is less than the minimum representable value of the signed type
735            /// (including $-\infty$), then it will be rounded to zero when the [`RoundingMode`] is
736            /// `Ceiling`, `Down`, or `Nearest`. Otherwise, this function will panic.
737            ///
738            /// If the [`Float`] is greater than the maximum representable value of the signed type
739            /// (including $\infty$), then it will be rounded to the maximum value when the
740            /// [`RoundingMode`] is `Floor`, `Down`, or `Nearest`. Otherwise, this function will
741            /// panic.
742            ///
743            /// If the [`Float`] is NaN, the function will panic regardless of the rounding mode.
744            ///
745            /// # Worst-case complexity
746            /// Constant time and additional memory.
747            ///
748            /// # Panics
749            /// Panics if the [`Float`] is not an integer and `rm` is `Exact`, or if the [`Float`]
750            /// is smaller than the minimum representable value of the signed type and `rm` is not
751            /// `Down`, `Ceiling`, or `Nearest`, if the [`Float`] is greater than the maximum
752            /// representable value of the signed type and `rm` is not `Down`, `Floor`, or
753            /// `Nearest`, or if the [`Float`] is NaN.
754            ///
755            /// # Examples
756            /// See [here](super::primitive_int_from_float#rounding_from).
757            #[inline]
758            fn rounding_from(f: &Float, rm: RoundingMode) -> ($t, Ordering) {
759                signed_rounding_from_float_ref(f, rm)
760            }
761        }
762
763        impl TryFrom<Float> for $t {
764            type Error = SignedFromFloatError;
765
766            /// Converts a [`Float`] to a primitive signed integer, taking the [`Float`] by value.
767            /// If the [`Float`] is not equal to a signed primitive integer of the given type, an
768            /// error is returned.
769            ///
770            /// # Worst-case complexity
771            /// Constant time and additional memory.
772            ///
773            /// # Examples
774            /// See [here](super::primitive_int_from_float#try_from).
775            #[inline]
776            fn try_from(f: Float) -> Result<$t, Self::Error> {
777                signed_try_from_float(f)
778            }
779        }
780
781        impl TryFrom<&Float> for $t {
782            type Error = SignedFromFloatError;
783
784            /// Converts a [`Float`] to a primitive signed integer, taking the [`Float`] by
785            /// reference. If the [`Float`] is not equal to a signed primitive integer of the given
786            /// type, an error is returned.
787            ///
788            /// # Worst-case complexity
789            /// Constant time and additional memory.
790            ///
791            /// # Examples
792            /// See [here](super::primitive_int_from_float#try_from).
793            #[inline]
794            fn try_from(f: &Float) -> Result<$t, Self::Error> {
795                signed_try_from_float_ref(f)
796            }
797        }
798
799        impl ConvertibleFrom<&Float> for $t {
800            /// Determines whether a [`Float`] can be converted to a signed primitive integer,
801            /// taking the [`Float`] by reference.
802            ///
803            /// # Worst-case complexity
804            /// Constant time and additional memory.
805            ///
806            /// # Examples
807            /// See [here](super::primitive_int_from_float#convertible_from).
808            #[inline]
809            fn convertible_from(f: &Float) -> bool {
810                signed_convertible_from_float::<$t>(f)
811            }
812        }
813    };
814}
815apply_to_signeds!(impl_signed_from);