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