Skip to main content

malachite_nz/natural/arithmetic/
log_base_power_of_2.rs

1// Copyright © 2026 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::natural::InnerNatural::{Large, Small};
10use crate::natural::Natural;
11use crate::natural::arithmetic::is_power_of_2::limbs_is_power_of_2;
12use crate::natural::logic::significant_bits::limbs_significant_bits;
13use crate::platform::Limb;
14use malachite_base::num::arithmetic::traits::{
15    CeilingLogBasePowerOf2, CheckedLogBasePowerOf2, DivMod, FloorLogBasePowerOf2,
16};
17
18// Given the limbs of a `Natural`, returns the floor of its base-$2^p$ logarithm.
19//
20// This function assumes that `xs` is nonempty and the last (most significant) limb is nonzero.
21//
22// $f((d_i)_ {i=0}^k, p) = \lfloor\log_{2^p} x\rfloor$, where $x = \sum_{i=0}^kB^id_i$ and $B$ is
23// one more than `Limb::MAX`.
24//
25// # Worst-case complexity
26// Constant time and additional memory.
27//
28// # Panics
29// Panics if `xs` is empty or `pow` is 0.
30pub_test! {limbs_floor_log_base_power_of_2(xs: &[Limb], pow: u64) -> u64 {
31    assert_ne!(pow, 0);
32    (limbs_significant_bits(xs) - 1) / pow
33}}
34
35// Given the limbs of a `Natural`, returns the ceiling of its base-$2^p$ logarithm.
36//
37// This function assumes that `xs` is nonempty and the last (most significant) limb is nonzero.
38//
39// $f((d_i)_ {i=0}^k, p) = \lceil\log_{2^p} x\rceil$, where $x = \sum_{i=0}^kB^id_i$ and $B$ is one
40// more than `Limb::MAX`.
41//
42// # Worst-case complexity
43// $T(n) = O(n)$
44//
45// $M(n) = O(1)$
46//
47// where $T$ is time, $M$ is additional memory, and $n$ is `xs.len()`.
48//
49// # Panics
50// Panics if `xs` is empty or `pow` is 0.
51pub_test! {limbs_ceiling_log_base_power_of_2(xs: &[Limb], pow: u64) -> u64 {
52    assert_ne!(pow, 0);
53    let significant_bits_m_1 = limbs_significant_bits(xs) - 1;
54    let (floor_log, rem) = significant_bits_m_1.div_mod(pow);
55    if limbs_is_power_of_2(xs) && rem == 0 {
56        floor_log
57    } else {
58        floor_log + 1
59    }
60}}
61
62// Given the limbs of a `Natural`, returns the its base-$2^p$ logarithm. If the `Natural` is not a
63// power of $2^p$, returns `None`.
64//
65// This function assumes that `xs` is nonempty and the last (most significant) limb is nonzero.
66//
67// $$
68// f((d_i)_ {i=0}^k, p) = \\begin{cases}
69//     \operatorname{Some}(\log_{2^p} x) & \text{if} \\quad \log_{2^p} x \in \Z, \\\\
70//     \operatorname{None} & \textrm{otherwise}.
71// \\end{cases}
72// $$
73// where $x = \sum_{i=0}^kB^id_i$ and $B$ is one more than `Limb::MAX`.
74//
75// # Worst-case complexity
76// $T(n) = O(n)$
77//
78// $M(n) = O(1)$
79//
80// where $T$ is time, $M$ is additional memory, and $n$ is `xs.len()`.
81//
82// # Panics
83// Panics if `xs` is empty or `pow` is 0.
84pub_test! {limbs_checked_log_base_power_of_2(xs: &[Limb], pow: u64) -> Option<u64> {
85    assert_ne!(pow, 0);
86    let significant_bits_m_1 = limbs_significant_bits(xs) - 1;
87    let (floor_log, rem) = significant_bits_m_1.div_mod(pow);
88    if limbs_is_power_of_2(xs) && rem == 0 {
89        Some(floor_log)
90    } else {
91        None
92    }
93}}
94
95impl FloorLogBasePowerOf2<u64> for &Natural {
96    type Output = u64;
97
98    /// Returns the floor of the base-$2^k$ logarithm of a positive [`Natural`].
99    ///
100    /// $f(x, k) = \lfloor\log_{2^k} x\rfloor$.
101    ///
102    /// # Worst-case complexity
103    /// Constant time and additional memory.
104    ///
105    /// # Panics
106    /// Panics if `self` is 0 or `pow` is 0.
107    ///
108    /// # Examples
109    /// ```
110    /// use malachite_base::num::arithmetic::traits::FloorLogBasePowerOf2;
111    /// use malachite_nz::natural::Natural;
112    ///
113    /// assert_eq!(Natural::from(100u32).floor_log_base_power_of_2(2), 3);
114    /// assert_eq!(Natural::from(4294967296u64).floor_log_base_power_of_2(8), 4);
115    /// ```
116    fn floor_log_base_power_of_2(self, pow: u64) -> u64 {
117        match self {
118            Natural(Small(small)) => small.floor_log_base_power_of_2(pow),
119            Natural(Large(limbs)) => limbs_floor_log_base_power_of_2(limbs, pow),
120        }
121    }
122}
123
124impl CeilingLogBasePowerOf2<u64> for &Natural {
125    type Output = u64;
126
127    /// Returns the ceiling of the base-$2^k$ logarithm of a positive [`Natural`].
128    ///
129    /// $f(x, k) = \lceil\log_{2^k} x\rceil$.
130    ///
131    /// # Worst-case complexity
132    /// $T(n) = O(n)$
133    ///
134    /// $M(n) = O(1)$
135    ///
136    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
137    ///
138    /// # Panics
139    /// Panics if `self` is 0 or `pow` is 0.
140    ///
141    /// # Examples
142    /// ```
143    /// use malachite_base::num::arithmetic::traits::CeilingLogBasePowerOf2;
144    /// use malachite_nz::natural::Natural;
145    ///
146    /// assert_eq!(Natural::from(100u32).ceiling_log_base_power_of_2(2), 4);
147    /// assert_eq!(
148    ///     Natural::from(4294967296u64).ceiling_log_base_power_of_2(8),
149    ///     4
150    /// );
151    /// ```
152    fn ceiling_log_base_power_of_2(self, pow: u64) -> u64 {
153        match self {
154            Natural(Small(small)) => small.ceiling_log_base_power_of_2(pow),
155            Natural(Large(limbs)) => limbs_ceiling_log_base_power_of_2(limbs, pow),
156        }
157    }
158}
159
160impl CheckedLogBasePowerOf2<u64> for &Natural {
161    type Output = u64;
162
163    /// Returns the base-$2^k$ logarithm of a positive [`Natural`]. If the [`Natural`] is not a
164    /// power of $2^k$, then `None` is returned.
165    ///
166    /// $$
167    /// f(x, k) = \\begin{cases}
168    ///     \operatorname{Some}(\log_{2^k} x) & \text{if} \\quad \log_{2^k} x \in \Z, \\\\
169    ///     \operatorname{None} & \textrm{otherwise}.
170    /// \\end{cases}
171    /// $$
172    ///
173    /// # Worst-case complexity
174    /// $T(n) = O(n)$
175    ///
176    /// $M(n) = O(1)$
177    ///
178    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
179    ///
180    /// # Panics
181    /// Panics if `self` is 0 or `pow` is 0.
182    ///
183    /// # Examples
184    /// ```
185    /// use malachite_base::num::arithmetic::traits::CheckedLogBasePowerOf2;
186    /// use malachite_nz::natural::Natural;
187    ///
188    /// assert_eq!(Natural::from(100u32).checked_log_base_power_of_2(2), None);
189    /// assert_eq!(
190    ///     Natural::from(4294967296u64).checked_log_base_power_of_2(8),
191    ///     Some(4)
192    /// );
193    /// ```
194    fn checked_log_base_power_of_2(self, pow: u64) -> Option<u64> {
195        match self {
196            Natural(Small(small)) => small.checked_log_base_power_of_2(pow),
197            Natural(Large(limbs)) => limbs_checked_log_base_power_of_2(limbs, pow),
198        }
199    }
200}