malachite_float/conversion/
primitive_float_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::{significand_bits, Float};
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 | Nearest => (T::MAX_FINITE, Less),
53                        Ceiling | Up => (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 | Nearest => (T::MAX_FINITE, Less),
66                                Ceiling | Up => (T::INFINITY, Greater),
67
68                                Exact => {
69                                    panic!("Float too large for exact conversion")
70                                }
71                            }
72                        } else {
73                            (
74                                T::from_integer_mantissa_and_exponent(
75                                    mantissa >> 1,
76                                    exponent - i64::wrapping_from(target_prec) + 2,
77                                )
78                                .unwrap(),
79                                o,
80                            )
81                        }
82                    } else {
83                        (
84                            T::from_integer_mantissa_and_exponent(
85                                mantissa,
86                                exponent - i64::wrapping_from(target_prec) + 1,
87                            )
88                            .unwrap(),
89                            o,
90                        )
91                    }
92                }
93            };
94            if sign {
95                (x, o)
96            } else {
97                (-x, o.reverse())
98            }
99        }
100    }
101}
102
103fn primitive_float_rounding_from_float_ref<T: PrimitiveFloat>(
104    f: &Float,
105    rm: RoundingMode,
106) -> (T, Ordering) {
107    match f {
108        float_nan!() => (T::NAN, Equal),
109        float_infinity!() => (T::INFINITY, Equal),
110        float_negative_infinity!() => (T::NEGATIVE_INFINITY, Equal),
111        float_zero!() => (T::ZERO, Equal),
112        float_negative_zero!() => (T::NEGATIVE_ZERO, Equal),
113        Float(Finite {
114            sign,
115            exponent,
116            significand,
117            ..
118        }) => {
119            let abs_rm = if *sign { rm } else { -rm };
120            let (x, o) = {
121                let exponent = i64::from(*exponent) - 1;
122                if exponent < T::MIN_EXPONENT {
123                    match abs_rm {
124                        Floor | Down => (T::ZERO, Less),
125                        Ceiling | Up => (T::MIN_POSITIVE_SUBNORMAL, Greater),
126                        Nearest => {
127                            if exponent == T::MIN_EXPONENT - 1 && !significand.is_power_of_2() {
128                                (T::MIN_POSITIVE_SUBNORMAL, Greater)
129                            } else {
130                                (T::ZERO, Less)
131                            }
132                        }
133                        Exact => panic!("Float too small for exact conversion"),
134                    }
135                } else if exponent > T::MAX_EXPONENT {
136                    match abs_rm {
137                        Floor | Down | Nearest => (T::MAX_FINITE, Less),
138                        Ceiling | Up => (T::INFINITY, Greater),
139                        Exact => panic!("Float too large for exact conversion"),
140                    }
141                } else {
142                    let target_prec = T::max_precision_for_sci_exponent(exponent);
143                    let bits = significand_bits(significand);
144                    let (mantissa, o) =
145                        significand.shr_round(i128::from(bits) - i128::from(target_prec), abs_rm);
146                    let mantissa = u64::wrapping_from(&mantissa);
147                    if mantissa.significant_bits() > target_prec {
148                        if exponent == T::MAX_EXPONENT {
149                            match abs_rm {
150                                Floor | Down | Nearest => (T::MAX_FINITE, Less),
151                                Ceiling | Up => (T::INFINITY, Greater),
152
153                                Exact => {
154                                    panic!("Float too large for exact conversion")
155                                }
156                            }
157                        } else {
158                            (
159                                T::from_integer_mantissa_and_exponent(
160                                    mantissa >> 1,
161                                    exponent - i64::wrapping_from(target_prec) + 2,
162                                )
163                                .unwrap(),
164                                o,
165                            )
166                        }
167                    } else {
168                        (
169                            T::from_integer_mantissa_and_exponent(
170                                mantissa,
171                                exponent - i64::wrapping_from(target_prec) + 1,
172                            )
173                            .unwrap(),
174                            o,
175                        )
176                    }
177                }
178            };
179            if *sign {
180                (x, o)
181            } else {
182                (-x, o.reverse())
183            }
184        }
185    }
186}
187
188#[derive(Clone, Copy, Debug, Eq, PartialEq)]
189pub enum FloatFromFloatError {
190    Overflow,
191    Underflow,
192    Inexact,
193}
194
195fn primitive_float_try_from_float<T: PrimitiveFloat>(f: Float) -> Result<T, FloatFromFloatError> {
196    match f {
197        float_nan!() => Ok(T::NAN),
198        float_infinity!() => Ok(T::INFINITY),
199        float_negative_infinity!() => Ok(T::NEGATIVE_INFINITY),
200        float_zero!() => Ok(T::ZERO),
201        float_negative_zero!() => Ok(T::NEGATIVE_ZERO),
202        Float(Finite {
203            sign,
204            exponent,
205            significand,
206            ..
207        }) => {
208            let x = {
209                let exponent = i64::from(exponent) - 1;
210                if exponent < T::MIN_EXPONENT {
211                    return Err(FloatFromFloatError::Underflow);
212                } else if exponent > T::MAX_EXPONENT {
213                    return Err(FloatFromFloatError::Overflow);
214                }
215                let target_prec = T::max_precision_for_sci_exponent(exponent);
216                let bits = significand_bits(&significand);
217                if bits > target_prec && !significand.divisible_by_power_of_2(bits - target_prec) {
218                    return Err(FloatFromFloatError::Inexact);
219                }
220                let mantissa = u64::wrapping_from(
221                    &(significand >> (i128::from(bits) - i128::from(target_prec))),
222                );
223                T::from_integer_mantissa_and_exponent(
224                    mantissa,
225                    exponent - i64::wrapping_from(target_prec) + 1,
226                )
227                .unwrap()
228            };
229            Ok(if sign { x } else { -x })
230        }
231    }
232}
233
234fn primitive_float_try_from_float_ref<T: PrimitiveFloat>(
235    f: &Float,
236) -> Result<T, FloatFromFloatError> {
237    match f {
238        float_nan!() => Ok(T::NAN),
239        float_infinity!() => Ok(T::INFINITY),
240        float_negative_infinity!() => Ok(T::NEGATIVE_INFINITY),
241        float_zero!() => Ok(T::ZERO),
242        float_negative_zero!() => Ok(T::NEGATIVE_ZERO),
243        Float(Finite {
244            sign,
245            exponent,
246            significand,
247            ..
248        }) => {
249            let x = if *significand == 0u32 {
250                T::ZERO
251            } else {
252                let exponent = i64::from(*exponent) - 1;
253                if exponent < T::MIN_EXPONENT {
254                    return Err(FloatFromFloatError::Underflow);
255                } else if exponent > T::MAX_EXPONENT {
256                    return Err(FloatFromFloatError::Overflow);
257                }
258                let target_prec = T::max_precision_for_sci_exponent(exponent);
259                let bits = significand_bits(significand);
260                if bits > target_prec && !significand.divisible_by_power_of_2(bits - target_prec) {
261                    return Err(FloatFromFloatError::Inexact);
262                }
263                let mantissa = u64::wrapping_from(
264                    &(significand >> (i128::from(bits) - i128::from(target_prec))),
265                );
266                T::from_integer_mantissa_and_exponent(
267                    mantissa,
268                    exponent - i64::wrapping_from(target_prec) + 1,
269                )
270                .unwrap()
271            };
272            Ok(if *sign { x } else { -x })
273        }
274    }
275}
276
277fn primitive_float_convertible_from_float<T: PrimitiveFloat>(f: &Float) -> bool {
278    match f {
279        Float(Finite {
280            exponent,
281            significand,
282            ..
283        }) => {
284            let exponent = i64::from(*exponent) - 1;
285            exponent >= T::MIN_EXPONENT && exponent <= T::MAX_EXPONENT && {
286                let target_prec = T::max_precision_for_sci_exponent(exponent);
287                let bits = significand_bits(significand);
288                bits <= target_prec || significand.divisible_by_power_of_2(bits - target_prec)
289            }
290        }
291        _ => true,
292    }
293}
294
295macro_rules! impl_primitive_float_from {
296    ($t: ident) => {
297        impl RoundingFrom<Float> for $t {
298            /// Converts a [`Float`] to a primitive float, using a specified [`RoundingMode`] and
299            /// taking the [`Float`] by value. An [`Ordering`] is also returned, indicating whether
300            /// the returned value is less than, equal to, or greater than the original value.
301            /// (Although a NaN is not comparable to any [`Float`], converting a NaN to a NaN will
302            /// also return `Equal`, indicating an exact conversion.)
303            ///
304            /// # Worst-case complexity
305            /// Constant time and additional memory.
306            ///
307            /// # Panics
308            /// Panics if the [`Float`] is not exactly equal to any float of the target type, and
309            /// `rm` is `Exact`.
310            ///
311            /// # Examples
312            /// See [here](super::primitive_float_from_float#rounding_from).
313            #[inline]
314            fn rounding_from(f: Float, rm: RoundingMode) -> ($t, Ordering) {
315                primitive_float_rounding_from_float(f, rm)
316            }
317        }
318
319        impl RoundingFrom<&Float> for $t {
320            /// Converts a [`Float`] to a primitive float, using a specified [`RoundingMode`] and
321            /// taking the [`Float`] by reference. An [`Ordering`] is also returned, indicating
322            /// whether the returned value is less than, equal to, or greater than the original
323            /// value. (Although a NaN is not comparable to any [`Float`], converting a NaN to a NaN
324            /// will also return `Equal`, indicating an exact conversion.)
325            ///
326            /// # Worst-case complexity
327            /// Constant time and additional memory.
328            ///
329            /// # Panics
330            /// Panics if the [`Float`] is not exactly equal to any float of the target type, and
331            /// `rm` is `Exact`.
332            ///
333            /// # Examples
334            /// See [here](super::primitive_float_from_float#rounding_from).
335            #[inline]
336            fn rounding_from(f: &Float, rm: RoundingMode) -> ($t, Ordering) {
337                primitive_float_rounding_from_float_ref(f, rm)
338            }
339        }
340
341        impl TryFrom<Float> for $t {
342            type Error = FloatFromFloatError;
343
344            /// Converts a [`Float`] to a primitive float, taking the [`Float`] by value. If the
345            /// [`Float`] is not equal to a primitive float of the given type, an error is returned.
346            ///
347            /// # Worst-case complexity
348            /// Constant time and additional memory.
349            ///
350            /// # Examples
351            /// See [here](super::primitive_float_from_float#try_from).
352            #[inline]
353            fn try_from(f: Float) -> Result<$t, Self::Error> {
354                primitive_float_try_from_float(f)
355            }
356        }
357
358        impl TryFrom<&Float> for $t {
359            type Error = FloatFromFloatError;
360
361            /// Converts a [`Float`] to a primitive float, taking the [`Float`] by reference. If the
362            /// [`Float`] is not equal to a primitive float of the given type, an error is returned.
363            ///
364            /// # Worst-case complexity
365            /// Constant time and additional memory.
366            ///
367            /// # Examples
368            /// See [here](super::primitive_float_from_float#try_from).
369            #[inline]
370            fn try_from(f: &Float) -> Result<$t, Self::Error> {
371                primitive_float_try_from_float_ref(f)
372            }
373        }
374
375        impl ConvertibleFrom<&Float> for $t {
376            /// Determines whether a [`Float`] can be converted to a primitive float, taking the
377            /// [`Float`] by reference.
378            ///
379            /// # Worst-case complexity
380            /// Constant time and additional memory.
381            ///
382            /// # Examples
383            /// See [here](super::primitive_float_from_float#convertible_from).
384            #[inline]
385            fn convertible_from(f: &Float) -> bool {
386                primitive_float_convertible_from_float::<$t>(f)
387            }
388        }
389    };
390}
391apply_to_primitive_floats!(impl_primitive_float_from);