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