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) -> (Float, Ordering) {
101 assert_ne!(prec, 0);
102 if let Ok(exponent) = i32::try_from(pow) {
103 if let Some(exponent) = exponent.checked_add(1) {
104 if (Float::MIN_EXPONENT..=Float::MAX_EXPONENT).contains(&exponent) {
105 return (
106 Float(Finite {
107 sign: true,
108 exponent,
109 precision: prec,
110 significand: Natural::power_of_2(
111 prec.round_to_multiple_of_power_of_2(Limb::LOG_WIDTH, Ceiling)
112 .0
113 - 1,
114 ),
115 }),
116 Equal,
117 );
118 }
119 }
120 }
121 match (pow > 0, rm) {
122 (_, Exact) => panic!("Inexact power_of_2"),
123 (true, Ceiling | Up | Nearest) => (Float::INFINITY, Greater),
124 (true, _) => (Float::max_finite_value_with_prec(prec), Less),
125 (false, Floor | Down | Nearest) => (Float::ZERO, Less),
126 (false, Ceiling | Up) => (Float::min_positive_value_prec(prec), Greater),
127 }
128 }
129
130 /// Raises 2 to an integer power, returning a [`Float`] with the specified precision. An
131 /// [`Ordering`] is also returned, indicating whether the returned power is less than, equal to,
132 /// or greater than the exact power. The ordering is usually `Equal`, but is `Greater` in the
133 /// case of overflow and `Less` in the case of underflow.
134 ///
135 /// $f(k) = 2^k$, and the result has precision `prec`.
136 ///
137 /// If `pow` is greater than $2^{30}-2$, $\infty$ is returned. If `pow` is less than $-2^{30}$,
138 /// positive zero is returned. If you want different overflow and underflow behavior, try using
139 /// `Float::power_of_2_prec_round` instead.
140 ///
141 /// If you need a [`Float`] with precision 1, then the [`PowerOf2`] implementation may be used
142 /// instead.
143 ///
144 /// # Panics
145 /// Panics if `prec` is zero.
146 ///
147 /// # Worst-case complexity
148 /// $T(n) = O(n)$
149 ///
150 /// $M(n) = O(n)$
151 ///
152 /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
153 ///
154 /// # Examples
155 /// ```
156 /// use malachite_base::num::arithmetic::traits::PowerOf2;
157 /// use malachite_float::Float;
158 /// use std::cmp::Ordering::*;
159 ///
160 /// let (p, o) = Float::power_of_2_prec(0, 1);
161 /// assert_eq!(p.to_string(), "1.0");
162 /// assert_eq!(o, Equal);
163 ///
164 /// let (p, o) = Float::power_of_2_prec(0, 100);
165 /// assert_eq!(p.to_string(), "1.0");
166 /// assert_eq!(o, Equal);
167 ///
168 /// let (p, o) = Float::power_of_2_prec(100, 1);
169 /// assert_eq!(p.to_string(), "1.0e30");
170 /// assert_eq!(o, Equal);
171 ///
172 /// let (p, o) = Float::power_of_2_prec(100, 100);
173 /// assert_eq!(p.to_string(), "1267650600228229401496703205376.0");
174 /// assert_eq!(o, Equal);
175 ///
176 /// let (p, o) = Float::power_of_2_prec(-100, 1);
177 /// assert_eq!(p.to_string(), "8.0e-31");
178 /// assert_eq!(o, Equal);
179 ///
180 /// let (p, o) = Float::power_of_2_prec(-100, 100);
181 /// assert_eq!(p.to_string(), "7.88860905221011805411728565283e-31");
182 /// assert_eq!(o, Equal);
183 ///
184 /// let (p, o) = Float::power_of_2_prec(i64::power_of_2(30) - 1, 10);
185 /// assert_eq!(p.to_string(), "Infinity");
186 /// assert_eq!(o, Greater);
187 ///
188 /// let (p, o) = Float::power_of_2_prec(-i64::power_of_2(30) - 1, 10);
189 /// assert_eq!(p.to_string(), "0.0");
190 /// assert_eq!(o, Less);
191 /// ```
192 #[inline]
193 pub fn power_of_2_prec(pow: i64, prec: u64) -> (Float, Ordering) {
194 Float::power_of_2_prec_round(pow, prec, Nearest)
195 }
196}
197
198impl PowerOf2<u64> for Float {
199 /// Raises 2 to an integer power, returning a [`Float`] with precision 1.
200 ///
201 /// To get a [`Float`] with a higher precision, try [`Float::power_of_2_prec`].
202 ///
203 /// $f(k) = 2^k$.
204 ///
205 /// If `pow` is greater than $2^{30}-2$, $\infty$ is returned.
206 ///
207 /// # Worst-case complexity
208 /// Constant time and additional memory.
209 ///
210 /// # Examples
211 /// ```
212 /// use malachite_base::num::arithmetic::traits::PowerOf2;
213 /// use malachite_float::Float;
214 ///
215 /// assert_eq!(Float::power_of_2(0u64).to_string(), "1.0");
216 /// assert_eq!(Float::power_of_2(3u64).to_string(), "8.0");
217 /// assert_eq!(Float::power_of_2(100u64).to_string(), "1.0e30");
218 /// assert_eq!(
219 /// Float::power_of_2(u64::power_of_2(30) - 1).to_string(),
220 /// "Infinity"
221 /// );
222 /// ```
223 fn power_of_2(pow: u64) -> Float {
224 if let Ok(exponent) = i32::try_from(pow) {
225 if let Some(exponent) = exponent.checked_add(1) {
226 if exponent <= Float::MAX_EXPONENT {
227 return Float(Finite {
228 sign: true,
229 exponent,
230 precision: 1,
231 significand: Natural::HIGH_BIT,
232 });
233 }
234 }
235 }
236 Float::INFINITY
237 }
238}
239
240impl PowerOf2<i64> for Float {
241 /// Raises 2 to an integer power, returning a [`Float`] with precision 1.
242 ///
243 /// To get a [`Float`] with a higher precision, try [`Float::power_of_2_prec`].
244 ///
245 /// $f(k) = 2^k$.
246 ///
247 /// If `pow` is greater than $2^{30}-2$, $\infty$ is returned. If `pow` is less than $-2^{30}$,
248 /// positive zero is returned.
249 ///
250 /// # Worst-case complexity
251 /// Constant time and additional memory.
252 ///
253 /// # Examples
254 /// ```
255 /// use malachite_base::num::arithmetic::traits::PowerOf2;
256 /// use malachite_float::Float;
257 ///
258 /// assert_eq!(Float::power_of_2(0i64).to_string(), "1.0");
259 /// assert_eq!(Float::power_of_2(3i64).to_string(), "8.0");
260 /// assert_eq!(Float::power_of_2(100i64).to_string(), "1.0e30");
261 /// assert_eq!(Float::power_of_2(-3i64).to_string(), "0.1");
262 /// assert_eq!(Float::power_of_2(-100i64).to_string(), "8.0e-31");
263 /// assert_eq!(
264 /// Float::power_of_2(i64::power_of_2(30) - 1).to_string(),
265 /// "Infinity"
266 /// );
267 /// assert_eq!(
268 /// Float::power_of_2(-i64::power_of_2(30) - 1).to_string(),
269 /// "0.0"
270 /// );
271 /// ```
272 #[inline]
273 fn power_of_2(pow: i64) -> Float {
274 if let Ok(exponent) = i32::try_from(pow) {
275 if let Some(exponent) = exponent.checked_add(1) {
276 if (Float::MIN_EXPONENT..=Float::MAX_EXPONENT).contains(&exponent) {
277 return Float(Finite {
278 sign: true,
279 exponent,
280 precision: 1,
281 significand: Natural::HIGH_BIT,
282 });
283 }
284 }
285 }
286 if pow > 0 {
287 Float::INFINITY
288 } else {
289 Float::ZERO
290 }
291 }
292}