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