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}