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}