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}