malachite_float/arithmetic/power_of_2.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 crate::InnerFloat::Finite;
11use core::cmp::Ordering::{self, *};
12use malachite_base::num::arithmetic::traits::{PowerOf2, RoundToMultipleOfPowerOf2};
13use malachite_base::num::basic::integers::PrimitiveInt;
14use malachite_base::num::basic::traits::{Infinity, Zero};
15use malachite_base::rounding_modes::RoundingMode::{self, *};
16use malachite_nz::natural::Natural;
17use malachite_nz::platform::Limb;
18
19impl Float {
20 /// Raises 2 to an integer power, returning a [`Float`] with the specified precision and with
21 /// the specified rounding mode. An [`Ordering`] is also returned, indicating whether the
22 /// returned power is less than, equal to, or greater than the exact power. The ordering is
23 /// usually `Equal`, but is `Less` or `Greater` if overflow or underflow occurs.
24 ///
25 /// $f(k) = 2^k$, and the result has precision `prec`.
26 ///
27 /// - If `pow` is greater than $2^{30}-2$ and `rm` is `Floor` or `Down`, the largest
28 /// representable `Float` with the given precision is returned.
29 /// - If `pow` is greater than $2^{30}-2$ and `rm` is `Ceiling` or `Up`, or `Nearest`, $\infty$
30 /// is returned.
31 /// - If `pow` is less than $-2^{30}$ and `rm` is `Floor`, `Down`, or `Nearest`, positive zero
32 /// is returned.
33 /// - If `pow` is less than $-2^{30}$ and `rm` is `Ceiling` or `Up`, the smallest positive
34 /// `Float` is returned.
35 ///
36 /// If you want the behavior of `Nearest` (that is, returning $\infty$ on overflow and positive
37 /// zero on underflow), you can use `Float::power_of_2_prec` instead.
38 ///
39 /// If you need a [`Float`] with precision 1, then the [`PowerOf2`] implementation may be used
40 /// instead.
41 ///
42 /// # Panics
43 /// Panics if `prec` is zero, or if `rm` is exact and `pow` is greater than $2^{30}-2$ or less
44 /// than $-2^{30}$.
45 ///
46 /// # Worst-case complexity
47 /// $T(n) = O(n)$
48 ///
49 /// $M(n) = O(n)$
50 ///
51 /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
52 ///
53 /// # Examples
54 /// ```
55 /// use malachite_base::num::arithmetic::traits::PowerOf2;
56 /// use malachite_base::rounding_modes::RoundingMode::*;
57 /// use malachite_float::Float;
58 /// use std::cmp::Ordering::*;
59 ///
60 /// let (p, o) = Float::power_of_2_prec_round(0, 1, Nearest);
61 /// assert_eq!(p.to_string(), "1.0");
62 /// assert_eq!(o, Equal);
63 ///
64 /// let (p, o) = Float::power_of_2_prec_round(0, 100, Nearest);
65 /// assert_eq!(p.to_string(), "1.0");
66 /// assert_eq!(o, Equal);
67 ///
68 /// let (p, o) = Float::power_of_2_prec_round(100, 1, Nearest);
69 /// assert_eq!(p.to_string(), "1.0e30");
70 /// assert_eq!(o, Equal);
71 ///
72 /// let (p, o) = Float::power_of_2_prec_round(100, 100, Nearest);
73 /// assert_eq!(p.to_string(), "1267650600228229401496703205376.0");
74 /// assert_eq!(o, Equal);
75 ///
76 /// let (p, o) = Float::power_of_2_prec_round(-100, 1, Nearest);
77 /// assert_eq!(p.to_string(), "8.0e-31");
78 /// assert_eq!(o, Equal);
79 ///
80 /// let (p, o) = Float::power_of_2_prec_round(-100, 100, Nearest);
81 /// assert_eq!(p.to_string(), "7.88860905221011805411728565283e-31");
82 /// assert_eq!(o, Equal);
83 ///
84 /// let (p, o) = Float::power_of_2_prec_round(i64::power_of_2(30) - 1, 10, Floor);
85 /// assert_eq!(p.to_string(), "too_big");
86 /// assert_eq!(o, Less);
87 ///
88 /// let (p, o) = Float::power_of_2_prec_round(i64::power_of_2(30) - 1, 10, Ceiling);
89 /// assert_eq!(p.to_string(), "Infinity");
90 /// assert_eq!(o, Greater);
91 ///
92 /// let (p, o) = Float::power_of_2_prec_round(-i64::power_of_2(30) - 1, 10, Floor);
93 /// assert_eq!(p.to_string(), "0.0");
94 /// assert_eq!(o, Less);
95 ///
96 /// let (p, o) = Float::power_of_2_prec_round(-i64::power_of_2(30) - 1, 10, Ceiling);
97 /// assert_eq!(p.to_string(), "too_small");
98 /// assert_eq!(o, Greater);
99 /// ```
100 pub fn power_of_2_prec_round(pow: i64, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
101 assert_ne!(prec, 0);
102 if let Ok(exponent) = i32::try_from(pow)
103 && let Some(exponent) = exponent.checked_add(1)
104 && (Self::MIN_EXPONENT..=Self::MAX_EXPONENT).contains(&exponent)
105 {
106 return (
107 Self(Finite {
108 sign: true,
109 exponent,
110 precision: prec,
111 significand: Natural::power_of_2(
112 prec.round_to_multiple_of_power_of_2(Limb::LOG_WIDTH, Ceiling)
113 .0
114 - 1,
115 ),
116 }),
117 Equal,
118 );
119 }
120 match (pow > 0, rm) {
121 (_, Exact) => panic!("Inexact power_of_2"),
122 (true, Ceiling | Up | Nearest) => (Self::INFINITY, Greater),
123 (true, _) => (Self::max_finite_value_with_prec(prec), Less),
124 (false, Floor | Down | Nearest) => (Self::ZERO, Less),
125 (false, Ceiling | Up) => (Self::min_positive_value_prec(prec), Greater),
126 }
127 }
128
129 /// Raises 2 to an integer power, returning a [`Float`] with the specified precision. An
130 /// [`Ordering`] is also returned, indicating whether the returned power is less than, equal to,
131 /// or greater than the exact power. The ordering is usually `Equal`, but is `Greater` in the
132 /// case of overflow and `Less` in the case of underflow.
133 ///
134 /// $f(k) = 2^k$, and the result has precision `prec`.
135 ///
136 /// If `pow` is greater than $2^{30}-2$, $\infty$ is returned. If `pow` is less than $-2^{30}$,
137 /// positive zero is returned. If you want different overflow and underflow behavior, try using
138 /// `Float::power_of_2_prec_round` instead.
139 ///
140 /// If you need a [`Float`] with precision 1, then the [`PowerOf2`] implementation may be used
141 /// instead.
142 ///
143 /// # Panics
144 /// Panics if `prec` is zero.
145 ///
146 /// # Worst-case complexity
147 /// $T(n) = O(n)$
148 ///
149 /// $M(n) = O(n)$
150 ///
151 /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
152 ///
153 /// # Examples
154 /// ```
155 /// use malachite_base::num::arithmetic::traits::PowerOf2;
156 /// use malachite_float::Float;
157 /// use std::cmp::Ordering::*;
158 ///
159 /// let (p, o) = Float::power_of_2_prec(0, 1);
160 /// assert_eq!(p.to_string(), "1.0");
161 /// assert_eq!(o, Equal);
162 ///
163 /// let (p, o) = Float::power_of_2_prec(0, 100);
164 /// assert_eq!(p.to_string(), "1.0");
165 /// assert_eq!(o, Equal);
166 ///
167 /// let (p, o) = Float::power_of_2_prec(100, 1);
168 /// assert_eq!(p.to_string(), "1.0e30");
169 /// assert_eq!(o, Equal);
170 ///
171 /// let (p, o) = Float::power_of_2_prec(100, 100);
172 /// assert_eq!(p.to_string(), "1267650600228229401496703205376.0");
173 /// assert_eq!(o, Equal);
174 ///
175 /// let (p, o) = Float::power_of_2_prec(-100, 1);
176 /// assert_eq!(p.to_string(), "8.0e-31");
177 /// assert_eq!(o, Equal);
178 ///
179 /// let (p, o) = Float::power_of_2_prec(-100, 100);
180 /// assert_eq!(p.to_string(), "7.88860905221011805411728565283e-31");
181 /// assert_eq!(o, Equal);
182 ///
183 /// let (p, o) = Float::power_of_2_prec(i64::power_of_2(30) - 1, 10);
184 /// assert_eq!(p.to_string(), "Infinity");
185 /// assert_eq!(o, Greater);
186 ///
187 /// let (p, o) = Float::power_of_2_prec(-i64::power_of_2(30) - 1, 10);
188 /// assert_eq!(p.to_string(), "0.0");
189 /// assert_eq!(o, Less);
190 /// ```
191 #[inline]
192 pub fn power_of_2_prec(pow: i64, prec: u64) -> (Self, Ordering) {
193 Self::power_of_2_prec_round(pow, prec, Nearest)
194 }
195}
196
197impl PowerOf2<u64> for Float {
198 /// Raises 2 to an integer power, returning a [`Float`] with precision 1.
199 ///
200 /// To get a [`Float`] with a higher precision, try [`Float::power_of_2_prec`].
201 ///
202 /// $f(k) = 2^k$.
203 ///
204 /// If `pow` is greater than $2^{30}-2$, $\infty$ is returned.
205 ///
206 /// # Worst-case complexity
207 /// Constant time and additional memory.
208 ///
209 /// # Examples
210 /// ```
211 /// use malachite_base::num::arithmetic::traits::PowerOf2;
212 /// use malachite_float::Float;
213 ///
214 /// assert_eq!(Float::power_of_2(0u64).to_string(), "1.0");
215 /// assert_eq!(Float::power_of_2(3u64).to_string(), "8.0");
216 /// assert_eq!(Float::power_of_2(100u64).to_string(), "1.0e30");
217 /// assert_eq!(
218 /// Float::power_of_2(u64::power_of_2(30) - 1).to_string(),
219 /// "Infinity"
220 /// );
221 /// ```
222 fn power_of_2(pow: u64) -> Self {
223 if let Ok(exponent) = i32::try_from(pow)
224 && let Some(exponent) = exponent.checked_add(1)
225 && exponent <= Self::MAX_EXPONENT
226 {
227 return Self(Finite {
228 sign: true,
229 exponent,
230 precision: 1,
231 significand: Natural::HIGH_BIT,
232 });
233 }
234 Self::INFINITY
235 }
236}
237
238impl PowerOf2<i64> for Float {
239 /// Raises 2 to an integer power, returning a [`Float`] with precision 1.
240 ///
241 /// To get a [`Float`] with a higher precision, try [`Float::power_of_2_prec`].
242 ///
243 /// $f(k) = 2^k$.
244 ///
245 /// If `pow` is greater than $2^{30}-2$, $\infty$ is returned. If `pow` is less than $-2^{30}$,
246 /// positive zero is returned.
247 ///
248 /// # Worst-case complexity
249 /// Constant time and additional memory.
250 ///
251 /// # Examples
252 /// ```
253 /// use malachite_base::num::arithmetic::traits::PowerOf2;
254 /// use malachite_float::Float;
255 ///
256 /// assert_eq!(Float::power_of_2(0i64).to_string(), "1.0");
257 /// assert_eq!(Float::power_of_2(3i64).to_string(), "8.0");
258 /// assert_eq!(Float::power_of_2(100i64).to_string(), "1.0e30");
259 /// assert_eq!(Float::power_of_2(-3i64).to_string(), "0.1");
260 /// assert_eq!(Float::power_of_2(-100i64).to_string(), "8.0e-31");
261 /// assert_eq!(
262 /// Float::power_of_2(i64::power_of_2(30) - 1).to_string(),
263 /// "Infinity"
264 /// );
265 /// assert_eq!(
266 /// Float::power_of_2(-i64::power_of_2(30) - 1).to_string(),
267 /// "0.0"
268 /// );
269 /// ```
270 #[inline]
271 fn power_of_2(pow: i64) -> Self {
272 if let Ok(exponent) = i32::try_from(pow)
273 && let Some(exponent) = exponent.checked_add(1)
274 && (Self::MIN_EXPONENT..=Self::MAX_EXPONENT).contains(&exponent)
275 {
276 return Self(Finite {
277 sign: true,
278 exponent,
279 precision: 1,
280 significand: Natural::HIGH_BIT,
281 });
282 }
283 if pow > 0 { Self::INFINITY } else { Self::ZERO }
284 }
285}