malachite_float/conversion/from_primitive_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::Float;
10use core::cmp::Ordering::{self, *};
11use malachite_base::num::basic::floats::PrimitiveFloat;
12use malachite_base::num::basic::traits::{Infinity, NaN, NegativeInfinity, NegativeZero, Zero};
13use malachite_base::num::conversion::traits::IntegerMantissaAndExponent;
14use malachite_base::rounding_modes::RoundingMode;
15
16impl Float {
17 /// Converts a primitive float to a [`Float`]. If the [`Float`] is nonzero and finite, it has
18 /// the specified precision. If rounding is needed, the specified rounding mode is used. An
19 /// [`Ordering`] is also returned, indicating whether the returned value is less than, equal to,
20 /// or greater than the original value. (Although a NaN is not comparable to any [`Float`],
21 /// converting a NaN to a NaN will also return `Equal`, indicating an exact conversion.)
22 ///
23 /// If you're only using `Nearest`, try using [`Float::from_primitive_float_prec`] instead.
24 ///
25 /// This function does not overflow or underflow.
26 ///
27 /// # Worst-case complexity
28 /// $T(n) = O(n)$
29 ///
30 /// $M(n) = O(n)$
31 ///
32 /// where $T$ is time, $M$ is additional memory, and $n$ is `max(prec, x.sci_exponent().abs())`.
33 ///
34 /// # Panics
35 /// Panics if `prec` is zero, or if `rm` is exact and the primitive float cannot be exactly
36 /// represented with the specified precision.
37 ///
38 /// # Examples
39 /// See [here](super::from_primitive_float#from_primitive_float_prec_round).
40 #[inline]
41 pub fn from_primitive_float_prec_round<T: PrimitiveFloat>(
42 x: T,
43 prec: u64,
44 rm: RoundingMode,
45 ) -> (Self, Ordering) {
46 assert_ne!(prec, 0);
47 if x.is_nan() {
48 (Self::NAN, Equal)
49 } else if !x.is_finite() {
50 if x.is_sign_positive() {
51 (Self::INFINITY, Equal)
52 } else {
53 (Self::NEGATIVE_INFINITY, Equal)
54 }
55 } else if x == T::ZERO {
56 if x.is_sign_positive() {
57 (Self::ZERO, Equal)
58 } else {
59 (Self::NEGATIVE_ZERO, Equal)
60 }
61 } else {
62 let (m, e) = x.integer_mantissa_and_exponent();
63 if x.is_sign_positive() {
64 let (f, o) = Self::from_unsigned_prec_round(m, prec, rm);
65 (f << e, o)
66 } else {
67 let (abs, o) = Self::from_unsigned_prec_round(m, prec, -rm);
68 (-(abs << e), o.reverse())
69 }
70 }
71 }
72
73 /// Converts a primitive float to a [`Float`]. If the [`Float`] is nonzero and finite, it has
74 /// the specified precision. An [`Ordering`] is also returned, indicating whether the returned
75 /// value is less than, equal to, or greater than the original value. (Although a NaN is not
76 /// comparable to any [`Float`], converting a NaN to a NaN will also return `Equal`, indicating
77 /// an exact conversion.)
78 ///
79 /// Rounding may occur, in which case `Nearest` is used by default. To specify a rounding mode
80 /// as well as a precision, try [`Float::from_primitive_float_prec_round`].
81 ///
82 /// This function does not overflow or underflow.
83 ///
84 /// # Worst-case complexity
85 /// $T(n) = O(n)$
86 ///
87 /// $M(n) = O(n)$
88 ///
89 /// where $T$ is time, $M$ is additional memory, and $n$ is `max(prec, x.sci_exponent().abs())`.
90 ///
91 /// # Panics
92 /// Panics if `prec` is zero.
93 ///
94 /// # Examples
95 /// See [here](super::from_primitive_float#from_primitive_float_prec).
96 #[inline]
97 pub fn from_primitive_float_prec<T: PrimitiveFloat>(x: T, prec: u64) -> (Self, Ordering) {
98 assert_ne!(prec, 0);
99 if x.is_nan() {
100 (Self::NAN, Equal)
101 } else if !x.is_finite() {
102 if x.is_sign_positive() {
103 (Self::INFINITY, Equal)
104 } else {
105 (Self::NEGATIVE_INFINITY, Equal)
106 }
107 } else if x == T::ZERO {
108 if x.is_sign_positive() {
109 (Self::ZERO, Equal)
110 } else {
111 (Self::NEGATIVE_ZERO, Equal)
112 }
113 } else {
114 let (m, e) = x.integer_mantissa_and_exponent();
115 if x.is_sign_positive() {
116 let (f, o) = Self::from_unsigned_prec(m, prec);
117 (f << e, o)
118 } else {
119 let (abs, o) = Self::from_unsigned_prec(m, prec);
120 (-(abs << e), o.reverse())
121 }
122 }
123 }
124}
125
126macro_rules! impl_from_primitive_float {
127 ($t: ident) => {
128 impl From<$t> for Float {
129 /// Converts a primitive float to a [`Float`].
130 ///
131 /// If the primitive float is finite and nonzero, the precision of the [`Float`] is the
132 /// minimum possible precision to represent the primitive float exactly. If you want to
133 /// specify a different precision, try [`Float::from_primitive_float_prec`]. This may
134 /// require rounding, which uses `Nearest` by default. To specify a rounding mode as
135 /// well as a precision, try [`Float::from_primitive_float_prec_round`].
136 ///
137 /// This function does not overflow or underflow.
138 ///
139 /// # Worst-case complexity
140 /// $T(n) = O(n)$
141 ///
142 /// $M(n) = O(n)$
143 ///
144 /// where $T$ is time, $M$ is additional memory, and $n$ is `x.sci_exponent().abs()`.
145 ///
146 /// # Examples
147 /// See [here](super::from_primitive_float#from).
148 #[inline]
149 fn from(x: $t) -> Float {
150 if x.is_nan() {
151 Float::NAN
152 } else if !x.is_finite() {
153 if x.is_sign_positive() {
154 Float::INFINITY
155 } else {
156 Float::NEGATIVE_INFINITY
157 }
158 } else if x == 0.0 {
159 if x.is_sign_positive() {
160 Float::ZERO
161 } else {
162 Float::NEGATIVE_ZERO
163 }
164 } else {
165 let (m, e) = x.integer_mantissa_and_exponent();
166 let abs = Float::from(m) << e;
167 if x.is_sign_positive() { abs } else { -abs }
168 }
169 }
170 }
171 };
172}
173apply_to_primitive_floats!(impl_from_primitive_float);