Skip to main content

malachite_float/float/conversion/
primitive_float_from_float.rs

1// Copyright © 2026 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::{Float, significand_bits};
11use core::cmp::Ordering::{self, *};
12use malachite_base::num::arithmetic::traits::{DivisibleByPowerOf2, IsPowerOf2, ShrRound};
13use malachite_base::num::basic::floats::PrimitiveFloat;
14use malachite_base::num::conversion::traits::{ConvertibleFrom, RoundingFrom, WrappingFrom};
15use malachite_base::num::logic::traits::SignificantBits;
16use malachite_base::rounding_modes::RoundingMode::{self, *};
17
18fn primitive_float_rounding_from_float<T: PrimitiveFloat>(
19    f: Float,
20    rm: RoundingMode,
21) -> (T, Ordering) {
22    match f {
23        float_nan!() => (T::NAN, Equal),
24        float_infinity!() => (T::INFINITY, Equal),
25        float_negative_infinity!() => (T::NEGATIVE_INFINITY, Equal),
26        float_zero!() => (T::ZERO, Equal),
27        float_negative_zero!() => (T::NEGATIVE_ZERO, Equal),
28        Float(Finite {
29            sign,
30            exponent,
31            significand,
32            ..
33        }) => {
34            let abs_rm = if sign { rm } else { -rm };
35            let (x, o) = {
36                let exponent = i64::from(exponent) - 1;
37                if exponent < T::MIN_EXPONENT {
38                    match abs_rm {
39                        Floor | Down => (T::ZERO, Less),
40                        Ceiling | Up => (T::MIN_POSITIVE_SUBNORMAL, Greater),
41                        Nearest => {
42                            if exponent == T::MIN_EXPONENT - 1 && !significand.is_power_of_2() {
43                                (T::MIN_POSITIVE_SUBNORMAL, Greater)
44                            } else {
45                                (T::ZERO, Less)
46                            }
47                        }
48                        Exact => panic!("Float too small for exact conversion"),
49                    }
50                } else if exponent > T::MAX_EXPONENT {
51                    match abs_rm {
52                        Floor | Down => (T::MAX_FINITE, Less),
53                        Ceiling | Up | Nearest => (T::INFINITY, Greater),
54                        Exact => panic!("Float too large for exact conversion"),
55                    }
56                } else {
57                    let target_prec = T::max_precision_for_sci_exponent(exponent);
58                    let bits = significand_bits(&significand);
59                    let (mantissa, o) =
60                        significand.shr_round(i128::from(bits) - i128::from(target_prec), abs_rm);
61                    let mantissa = u64::wrapping_from(&mantissa);
62                    if mantissa.significant_bits() > target_prec {
63                        if exponent == T::MAX_EXPONENT {
64                            match abs_rm {
65                                Floor | Down => (T::MAX_FINITE, Less),
66                                Ceiling | Up | Nearest => (T::INFINITY, Greater),
67                                Exact => {
68                                    panic!("Float too large for exact conversion")
69                                }
70                            }
71                        } else {
72                            (
73                                T::from_integer_mantissa_and_exponent(
74                                    mantissa >> 1,
75                                    exponent - i64::wrapping_from(target_prec) + 2,
76                                )
77                                .unwrap(),
78                                o,
79                            )
80                        }
81                    } else {
82                        (
83                            T::from_integer_mantissa_and_exponent(
84                                mantissa,
85                                exponent - i64::wrapping_from(target_prec) + 1,
86                            )
87                            .unwrap(),
88                            o,
89                        )
90                    }
91                }
92            };
93            if sign { (x, o) } else { (-x, o.reverse()) }
94        }
95    }
96}
97
98fn primitive_float_rounding_from_float_ref<T: PrimitiveFloat>(
99    f: &Float,
100    rm: RoundingMode,
101) -> (T, Ordering) {
102    match f {
103        float_nan!() => (T::NAN, Equal),
104        float_infinity!() => (T::INFINITY, Equal),
105        float_negative_infinity!() => (T::NEGATIVE_INFINITY, Equal),
106        float_zero!() => (T::ZERO, Equal),
107        float_negative_zero!() => (T::NEGATIVE_ZERO, Equal),
108        Float(Finite {
109            sign,
110            exponent,
111            significand,
112            ..
113        }) => {
114            let abs_rm = if *sign { rm } else { -rm };
115            let (x, o) = {
116                let exponent = i64::from(*exponent) - 1;
117                if exponent < T::MIN_EXPONENT {
118                    match abs_rm {
119                        Floor | Down => (T::ZERO, Less),
120                        Ceiling | Up => (T::MIN_POSITIVE_SUBNORMAL, Greater),
121                        Nearest => {
122                            if exponent == T::MIN_EXPONENT - 1 && !significand.is_power_of_2() {
123                                (T::MIN_POSITIVE_SUBNORMAL, Greater)
124                            } else {
125                                (T::ZERO, Less)
126                            }
127                        }
128                        Exact => panic!("Float too small for exact conversion"),
129                    }
130                } else if exponent > T::MAX_EXPONENT {
131                    match abs_rm {
132                        Floor | Down => (T::MAX_FINITE, Less),
133                        Ceiling | Up | Nearest => (T::INFINITY, Greater),
134                        Exact => panic!("Float too large for exact conversion"),
135                    }
136                } else {
137                    let target_prec = T::max_precision_for_sci_exponent(exponent);
138                    let bits = significand_bits(significand);
139                    let (mantissa, o) =
140                        significand.shr_round(i128::from(bits) - i128::from(target_prec), abs_rm);
141                    let mantissa = u64::wrapping_from(&mantissa);
142                    if mantissa.significant_bits() > target_prec {
143                        if exponent == T::MAX_EXPONENT {
144                            match abs_rm {
145                                Floor | Down => (T::MAX_FINITE, Less),
146                                Ceiling | Up | Nearest => (T::INFINITY, Greater),
147
148                                Exact => {
149                                    panic!("Float too large for exact conversion")
150                                }
151                            }
152                        } else {
153                            (
154                                T::from_integer_mantissa_and_exponent(
155                                    mantissa >> 1,
156                                    exponent - i64::wrapping_from(target_prec) + 2,
157                                )
158                                .unwrap(),
159                                o,
160                            )
161                        }
162                    } else {
163                        (
164                            T::from_integer_mantissa_and_exponent(
165                                mantissa,
166                                exponent - i64::wrapping_from(target_prec) + 1,
167                            )
168                            .unwrap(),
169                            o,
170                        )
171                    }
172                }
173            };
174            if *sign { (x, o) } else { (-x, o.reverse()) }
175        }
176    }
177}
178
179#[derive(Clone, Copy, Debug, Eq, PartialEq)]
180pub enum FloatFromFloatError {
181    Overflow,
182    Underflow,
183    Inexact,
184}
185
186fn primitive_float_try_from_float<T: PrimitiveFloat>(f: Float) -> Result<T, FloatFromFloatError> {
187    match f {
188        float_nan!() => Ok(T::NAN),
189        float_infinity!() => Ok(T::INFINITY),
190        float_negative_infinity!() => Ok(T::NEGATIVE_INFINITY),
191        float_zero!() => Ok(T::ZERO),
192        float_negative_zero!() => Ok(T::NEGATIVE_ZERO),
193        Float(Finite {
194            sign,
195            exponent,
196            significand,
197            ..
198        }) => {
199            let x = {
200                let exponent = i64::from(exponent) - 1;
201                if exponent < T::MIN_EXPONENT {
202                    return Err(FloatFromFloatError::Underflow);
203                } else if exponent > T::MAX_EXPONENT {
204                    return Err(FloatFromFloatError::Overflow);
205                }
206                let target_prec = T::max_precision_for_sci_exponent(exponent);
207                let bits = significand_bits(&significand);
208                if bits > target_prec && !significand.divisible_by_power_of_2(bits - target_prec) {
209                    return Err(FloatFromFloatError::Inexact);
210                }
211                let mantissa = u64::wrapping_from(
212                    &(significand >> (i128::from(bits) - i128::from(target_prec))),
213                );
214                T::from_integer_mantissa_and_exponent(
215                    mantissa,
216                    exponent - i64::wrapping_from(target_prec) + 1,
217                )
218                .unwrap()
219            };
220            Ok(if sign { x } else { -x })
221        }
222    }
223}
224
225fn primitive_float_try_from_float_ref<T: PrimitiveFloat>(
226    f: &Float,
227) -> Result<T, FloatFromFloatError> {
228    match f {
229        float_nan!() => Ok(T::NAN),
230        float_infinity!() => Ok(T::INFINITY),
231        float_negative_infinity!() => Ok(T::NEGATIVE_INFINITY),
232        float_zero!() => Ok(T::ZERO),
233        float_negative_zero!() => Ok(T::NEGATIVE_ZERO),
234        Float(Finite {
235            sign,
236            exponent,
237            significand,
238            ..
239        }) => {
240            let x = if *significand == 0u32 {
241                T::ZERO
242            } else {
243                let exponent = i64::from(*exponent) - 1;
244                if exponent < T::MIN_EXPONENT {
245                    return Err(FloatFromFloatError::Underflow);
246                } else if exponent > T::MAX_EXPONENT {
247                    return Err(FloatFromFloatError::Overflow);
248                }
249                let target_prec = T::max_precision_for_sci_exponent(exponent);
250                let bits = significand_bits(significand);
251                if bits > target_prec && !significand.divisible_by_power_of_2(bits - target_prec) {
252                    return Err(FloatFromFloatError::Inexact);
253                }
254                let mantissa = u64::wrapping_from(
255                    &(significand >> (i128::from(bits) - i128::from(target_prec))),
256                );
257                T::from_integer_mantissa_and_exponent(
258                    mantissa,
259                    exponent - i64::wrapping_from(target_prec) + 1,
260                )
261                .unwrap()
262            };
263            Ok(if *sign { x } else { -x })
264        }
265    }
266}
267
268fn primitive_float_convertible_from_float<T: PrimitiveFloat>(f: &Float) -> bool {
269    match f {
270        Float(Finite {
271            exponent,
272            significand,
273            ..
274        }) => {
275            let exponent = i64::from(*exponent) - 1;
276            exponent >= T::MIN_EXPONENT && exponent <= T::MAX_EXPONENT && {
277                let target_prec = T::max_precision_for_sci_exponent(exponent);
278                let bits = significand_bits(significand);
279                bits <= target_prec || significand.divisible_by_power_of_2(bits - target_prec)
280            }
281        }
282        _ => true,
283    }
284}
285
286macro_rules! impl_primitive_float_from {
287    ($t: ident) => {
288        impl RoundingFrom<Float> for $t {
289            /// Converts a [`Float`] to a primitive float, using a specified [`RoundingMode`] and
290            /// taking the [`Float`] by value. An [`Ordering`] is also returned, indicating whether
291            /// the returned value is less than, equal to, or greater than the original value.
292            /// (Although a NaN is not comparable to any [`Float`], converting a NaN to a NaN will
293            /// also return `Equal`, indicating an exact conversion.)
294            ///
295            /// Overflow and underflow:
296            /// - If the rounding mode is `Floor`, the largest primitive float less than or equal to
297            ///   the [`Float`] is returned. If the [`Float`] is greater than the maximum finite
298            ///   primitive float, then the maximum finite primitive float is returned. If it is
299            ///   smaller than the minimum finite primitive float, then $-\infty$ is returned. If it
300            ///   is between zero and the minimum positive primitive float, then positive zero is
301            ///   returned.
302            /// - If the rounding mode is `Ceiling`, the smallest primitive float greater than or
303            ///   equal to the [`Float`] is returned. If the [`Float`] is greater than the maximum
304            ///   finite primitive float, then $\infty$ is returned. If it is smaller than the
305            ///   minimum finite primitive float, then the minimum finite primitive float is
306            ///   returned. If it is between zero and the maximum negative primitive float, then
307            ///   negative zero is returned.
308            /// - If the rounding mode is `Down`, then the rounding proceeds as with `Floor` if the
309            ///   [`Float`] is non-negative and as with `Ceiling` if the [`Float`] is negative. If
310            ///   the [`Float`] is between the maximum negative primitive float and the minimum
311            ///   positive primitive float, then positive zero is returned when the [`Float`] is
312            ///   non-negative and negative zero otherwise.
313            /// - If the rounding mode is `Up`, then the rounding proceeds as with `Ceiling` if the
314            ///   [`Float`] is non-negative and as with `Floor` if the [`Float`] is negative. Zero
315            ///   is only returned when the [`Float`] is zero.
316            /// - If the rounding mode is `Nearest`, then the nearest primitive float is returned.
317            ///   If the [`Float`] is exactly between two primitive floats, the primitive float with
318            ///   the zero least-significant bit in its representation is selected. If the [`Float`]
319            ///   is greater than the maximum finite primitive float, then $\infty$ is returned. If
320            ///   the [`Float`] is smaller than the minimum finite primitive float, then $-\infty$
321            ///   is returned. If the [`Float`] is closer to zero than to any other primitive float
322            ///   (or if there is a tie between zero and another float), then positive or negative
323            ///   zero is returned, depending on the [`Float`]'s sign.
324            ///
325            /// # Worst-case complexity
326            /// $T(n) = O(n)$
327            ///
328            /// $M(n) = O(1)$
329            ///
330            /// where $T$ is time, $M$ is additional memory, and $n$ is `f.significant_bits()`:
331            /// rounding must examine the bits that are discarded.
332            ///
333            /// # Panics
334            /// Panics if the [`Float`] is not exactly equal to any float of the target type, and
335            /// `rm` is `Exact`.
336            ///
337            /// # Examples
338            /// See [here](super::primitive_float_from_float#rounding_from).
339            #[inline]
340            fn rounding_from(f: Float, rm: RoundingMode) -> ($t, Ordering) {
341                primitive_float_rounding_from_float(f, rm)
342            }
343        }
344
345        impl RoundingFrom<&Float> for $t {
346            /// Converts a [`Float`] to a primitive float, using a specified [`RoundingMode`] and
347            /// taking the [`Float`] by reference. An [`Ordering`] is also returned, indicating
348            /// whether the returned value is less than, equal to, or greater than the original
349            /// value. (Although a NaN is not comparable to any [`Float`], converting a NaN to a NaN
350            /// will also return `Equal`, indicating an exact conversion.)
351            ///
352            /// Overflow and underflow:
353            /// - If the rounding mode is `Floor`, the largest primitive float less than or equal to
354            ///   the [`Float`] is returned. If the [`Float`] is greater than the maximum finite
355            ///   primitive float, then the maximum finite primitive float is returned. If it is
356            ///   smaller than the minimum finite primitive float, then $-\infty$ is returned. If it
357            ///   is between zero and the minimum positive primitive float, then positive zero is
358            ///   returned.
359            /// - If the rounding mode is `Ceiling`, the smallest primitive float greater than or
360            ///   equal to the [`Float`] is returned. If the [`Float`] is greater than the maximum
361            ///   finite primitive float, then $\infty$ is returned. If it is smaller than the
362            ///   minimum finite primitive float, then the minimum finite primitive float is
363            ///   returned. If it is between zero and the maximum negative primitive float, then
364            ///   negative zero is returned.
365            /// - If the rounding mode is `Down`, then the rounding proceeds as with `Floor` if the
366            ///   [`Float`] is non-negative and as with `Ceiling` if the [`Float`] is negative. If
367            ///   the [`Float`] is between the maximum negative primitive float and the minimum
368            ///   positive primitive float, then positive zero is returned when the [`Float`] is
369            ///   non-negative and negative zero otherwise.
370            /// - If the rounding mode is `Up`, then the rounding proceeds as with `Ceiling` if the
371            ///   [`Float`] is non-negative and as with `Floor` if the [`Float`] is negative. Zero
372            ///   is only returned when the [`Float`] is zero.
373            /// - If the rounding mode is `Nearest`, then the nearest primitive float is returned.
374            ///   If the [`Float`] is exactly between two primitive floats, the primitive float with
375            ///   the zero least-significant bit in its representation is selected. If the [`Float`]
376            ///   is greater than the maximum finite primitive float, then $\infty$ is returned. If
377            ///   the [`Float`] is smaller than the minimum finite primitive float, then $-\infty$
378            ///   is returned. If the [`Float`] is closer to zero than to any other primitive float
379            ///   (or if there is a tie between zero and another float), then positive or negative
380            ///   zero is returned, depending on the [`Float`]'s sign.
381            ///
382            /// # Worst-case complexity
383            /// $T(n) = O(n)$
384            ///
385            /// $M(n) = O(1)$
386            ///
387            /// where $T$ is time, $M$ is additional memory, and $n$ is `f.significant_bits()`:
388            /// rounding must examine the bits that are discarded.
389            ///
390            /// # Panics
391            /// Panics if the [`Float`] is not exactly equal to any float of the target type, and
392            /// `rm` is `Exact`.
393            ///
394            /// # Examples
395            /// See [here](super::primitive_float_from_float#rounding_from).
396            #[inline]
397            fn rounding_from(f: &Float, rm: RoundingMode) -> ($t, Ordering) {
398                primitive_float_rounding_from_float_ref(f, rm)
399            }
400        }
401
402        impl TryFrom<Float> for $t {
403            type Error = FloatFromFloatError;
404
405            /// Converts a [`Float`] to a primitive float, taking the [`Float`] by value. If the
406            /// [`Float`] is not equal to a primitive float of the given type, an error is returned.
407            ///
408            /// # Worst-case complexity
409            /// $T(n) = O(n)$
410            ///
411            /// $M(n) = O(1)$
412            ///
413            /// where $T$ is time, $M$ is additional memory, and $n$ is `f.significant_bits()`:
414            /// rounding must examine the bits that are discarded.
415            ///
416            /// # Examples
417            /// See [here](super::primitive_float_from_float#try_from).
418            #[inline]
419            fn try_from(f: Float) -> Result<$t, Self::Error> {
420                primitive_float_try_from_float(f)
421            }
422        }
423
424        impl TryFrom<&Float> for $t {
425            type Error = FloatFromFloatError;
426
427            /// Converts a [`Float`] to a primitive float, taking the [`Float`] by reference. If the
428            /// [`Float`] is not equal to a primitive float of the given type, an error is returned.
429            ///
430            /// # Worst-case complexity
431            /// $T(n) = O(n)$
432            ///
433            /// $M(n) = O(1)$
434            ///
435            /// where $T$ is time, $M$ is additional memory, and $n$ is `f.significant_bits()`:
436            /// rounding must examine the bits that are discarded.
437            ///
438            /// # Examples
439            /// See [here](super::primitive_float_from_float#try_from).
440            #[inline]
441            fn try_from(f: &Float) -> Result<$t, Self::Error> {
442                primitive_float_try_from_float_ref(f)
443            }
444        }
445
446        impl ConvertibleFrom<&Float> for $t {
447            /// Determines whether a [`Float`] can be converted to a primitive float, taking the
448            /// [`Float`] by reference.
449            ///
450            /// # Worst-case complexity
451            /// $T(n) = O(n)$
452            ///
453            /// $M(n) = O(1)$
454            ///
455            /// where $T$ is time, $M$ is additional memory, and $n$ is `f.significant_bits()`:
456            /// rounding must examine the bits that are discarded.
457            ///
458            /// # Examples
459            /// See [here](super::primitive_float_from_float#convertible_from).
460            #[inline]
461            fn convertible_from(f: &Float) -> bool {
462                primitive_float_convertible_from_float::<$t>(f)
463            }
464        }
465    };
466}
467apply_to_primitive_floats!(impl_primitive_float_from);