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