1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
/*
Copyright 2024 Owain Davies
SPDX-License-Identifier: Apache-2.0 OR MIT
*/
use crate::{Arbi, BitCount};
impl Arbi {
/// Returns the base 2 logarithm of the number, rounded down.
///
/// # Panics
/// This function will panic if `self` is less than or equal to zero.
///
/// # Examples
/// ```
/// use arbi::{Arbi, BitCount};
///
/// let a = Arbi::from(2);
/// assert_eq!(a.ilog2(), 1);
/// // assert_eq!(2_i32.ilog2(), 1); // rustc >= 1.67.0
///
/// let b = Arbi::from(123456789_i32);
/// assert_eq!(b.ilog2(), 26);
/// // assert_eq!(123456789_i32.ilog2(), 26); // rustc >= 1.67.0
///
/// let c = Arbi::from(u128::MAX);
/// // assert_eq!(c.ilog2(), u128::MAX.ilog2() as BitCount); // rustc >= 1.67.0
/// ```
///
/// This function will panic if `self` is zero or negative:
/// ```should_panic
/// use arbi::Arbi;
/// let a = Arbi::zero();
/// a.ilog2();
/// ```
///
/// ```should_panic
/// use arbi::Arbi;
/// let a = Arbi::neg_one();
/// a.ilog2();
/// ```
///
/// ## Complexity
/// \\( O(1) \\)
pub fn ilog2(&self) -> BitCount {
if self <= 0 {
panic!("self must be positive: {self}")
}
self.size_bits() - 1
}
}
#[cfg(test)]
mod tests {
use crate::uints::UnsignedUtilities;
use crate::util::test::{get_seedable_rng, get_uniform_die, Distribution};
use crate::{Arbi, BitCount, DDigit, Digit, QDigit};
#[test]
fn test_digit_boundaries() {
let a = Arbi::from(Digit::MAX);
assert_eq!(a.ilog2(), Digit::ilog2_(Digit::MAX) as BitCount);
let a = Arbi::from(Digit::MAX as DDigit + 1);
assert_eq!(
a.ilog2(),
DDigit::ilog2_(Digit::MAX as DDigit + 1) as BitCount
);
let a = Arbi::from(DDigit::MAX);
assert_eq!(a.ilog2(), DDigit::ilog2_(DDigit::MAX) as BitCount);
let a = Arbi::from(DDigit::MAX as QDigit + 1);
assert_eq!(
a.ilog2(),
QDigit::ilog2_(DDigit::MAX as QDigit + 1) as BitCount
);
}
#[test]
#[should_panic = "self must be positive: 0"]
fn test_zero() {
let a = Arbi::zero();
a.ilog2();
}
#[test]
#[should_panic = "self must be positive: -4"]
fn test_is_power_of_two_negative() {
let a = Arbi::from(-4);
a.ilog2();
}
#[test]
fn smoke() {
let (mut rng, _) = get_seedable_rng();
let die_digit = get_uniform_die(Digit::MIN, Digit::MAX);
let die_ddigit = get_uniform_die(Digit::MAX as DDigit + 1, DDigit::MAX);
let die_qdigit =
get_uniform_die(DDigit::MAX as QDigit + 1, QDigit::MAX);
for _ in 0..i16::MAX {
let r = die_digit.sample(&mut rng);
let a = Arbi::from(r);
assert_eq!(a.ilog2(), Digit::ilog2_(r) as BitCount);
let r = die_ddigit.sample(&mut rng);
let a = Arbi::from(r);
assert_eq!(a.ilog2(), DDigit::ilog2_(r) as BitCount);
let r = die_qdigit.sample(&mut rng);
let a = Arbi::from(r);
assert_eq!(a.ilog2(), QDigit::ilog2_(r) as BitCount);
}
}
}