/src/rust-brotli/src/enc/util.rs
Line | Count | Source |
1 | | #![allow(clippy::excessive_precision)] |
2 | | |
3 | | use crate::enc::log_table_16::logs_16; |
4 | | use crate::enc::log_table_8::logs_8; |
5 | | |
6 | | #[cfg(feature = "float64")] |
7 | | pub type floatX = f64; |
8 | | |
9 | | #[cfg(not(feature = "float64"))] |
10 | | pub type floatX = f32; |
11 | | |
12 | | #[inline(always)] |
13 | 0 | pub fn FastLog2u16(v: u16) -> floatX { |
14 | 0 | logs_16[v as usize] |
15 | 0 | } |
16 | | |
17 | | // The `portable-float` feature routes `std` builds onto the table-driven |
18 | | // implementations below, which are the same ones `no_std` builds already use. |
19 | | // They contain no calls into the platform's libm, so the encoder's cost |
20 | | // estimates -- and therefore the bytes it emits -- are identical on every |
21 | | // target. The feature is a no-op for `no_std` builds: those are already |
22 | | // portable, because the libm path is unavailable to them in the first place. |
23 | | |
24 | | #[cfg(all(feature = "std", not(feature = "portable-float")))] |
25 | | #[inline(always)] |
26 | 0 | pub fn FastLog2(v: u64) -> floatX { |
27 | 0 | if v < 256 { |
28 | 0 | logs_8[v as usize] |
29 | | } else { |
30 | 0 | (v as f32).log2() as floatX |
31 | | } |
32 | 0 | } |
33 | | |
34 | | #[cfg(any(not(feature = "std"), feature = "portable-float"))] |
35 | | #[inline(always)] |
36 | | pub fn FastLog2(v: u64) -> floatX { |
37 | | if v < 256 { |
38 | | logs_8[v as usize] |
39 | | } else { |
40 | | FastLog2u64(v) |
41 | | } |
42 | | } |
43 | | |
44 | | #[cfg(all(feature = "std", not(feature = "portable-float")))] |
45 | | #[inline(always)] |
46 | 0 | pub fn FastLog2f64(v: u64) -> floatX { |
47 | 0 | if v < 256 { |
48 | 0 | logs_8[v as usize] |
49 | | } else { |
50 | 0 | (v as floatX).log2() |
51 | | } |
52 | 0 | } |
53 | | |
54 | | #[cfg(any(not(feature = "std"), feature = "portable-float"))] |
55 | | #[inline(always)] |
56 | | pub fn FastLog2f64(v: u64) -> floatX { |
57 | | FastLog2(v) as floatX |
58 | | } |
59 | | |
60 | | #[inline] |
61 | 0 | pub fn FastLog2u64(v: u64) -> floatX { |
62 | 0 | let bsr_8 = 56i8 - v.leading_zeros() as i8; |
63 | 0 | let offset = bsr_8 & -((bsr_8 >= 0) as i8); |
64 | 0 | (offset as floatX) + logs_8[(v >> offset) as usize] |
65 | 0 | } |
66 | | |
67 | | #[inline(always)] |
68 | 0 | pub fn FastLog2u32(v: i32) -> floatX { |
69 | 0 | let bsr_8 = 24i8 - v.leading_zeros() as i8; |
70 | 0 | let offset = bsr_8 & -((bsr_8 >= 0) as i8); |
71 | 0 | (offset as floatX) + logs_8[(v >> offset) as usize] |
72 | 0 | } |
73 | | |
74 | | #[inline(always)] |
75 | 0 | pub fn xFastLog2u16(v: u16) -> floatX { |
76 | 0 | let bsr_8 = 8i8 - v.leading_zeros() as i8; |
77 | 0 | let offset = (bsr_8 & -((bsr_8 >= 0) as i8)); |
78 | 0 | (offset as floatX) + logs_8[(v >> offset) as usize] |
79 | 0 | } |
80 | | |
81 | | #[cfg(all(feature = "std", not(feature = "portable-float")))] |
82 | | #[inline(always)] |
83 | 0 | pub fn FastPow2(v: floatX) -> floatX { |
84 | 0 | (2 as floatX).powf(v) |
85 | 0 | } |
86 | | |
87 | | #[cfg(any(not(feature = "std"), feature = "portable-float"))] |
88 | | #[inline(always)] |
89 | | pub fn FastPow2(v: floatX) -> floatX { |
90 | | assert!(v >= 0 as floatX); |
91 | | let round_down = v as i32; |
92 | | let remainder = v - round_down as floatX; |
93 | | let mut x = 1 as floatX; |
94 | | // (1 + (x/n) * ln2) ^ n |
95 | | // let n = 8 |
96 | | x += remainder * (0.693147180559945309417232121458 / 256.0) as floatX; |
97 | | x *= x; |
98 | | x *= x; |
99 | | x *= x; |
100 | | x *= x; |
101 | | x *= x; |
102 | | x *= x; |
103 | | x *= x; |
104 | | x *= x; |
105 | | |
106 | | (1 << round_down) as floatX * x |
107 | | } |
108 | | |
109 | | #[inline(always)] |
110 | 0 | pub fn Log2FloorNonZero(v: u64) -> u32 { |
111 | 0 | 63u32 ^ v.leading_zeros() |
112 | 0 | } |
113 | | |
114 | | #[cfg(test)] |
115 | | mod test { |
116 | | fn baseline_log2_floor_non_zero(mut n: u64) -> u32 { |
117 | | let mut result: u32 = 0; |
118 | | while { |
119 | | n >>= 1i32; |
120 | | n |
121 | | } != 0 |
122 | | { |
123 | | result = result.wrapping_add(1); |
124 | | } |
125 | | result |
126 | | } |
127 | | |
128 | | #[test] |
129 | | fn log2floor_non_zero_works() { |
130 | | let examples = [ |
131 | | 4u64, |
132 | | 254, |
133 | | 256, |
134 | | 1428, |
135 | | 25412509, |
136 | | 21350891256, |
137 | | 65536, |
138 | | 1258912591, |
139 | | 60968101, |
140 | | 1, |
141 | | 12589125190825, |
142 | | 105912059215091, |
143 | | 0, |
144 | | ]; |
145 | | for example in examples.iter() { |
146 | | let fast_version = super::Log2FloorNonZero(*example); |
147 | | let baseline_version = baseline_log2_floor_non_zero(*example); |
148 | | if *example != 0 { |
149 | | // make sure we don't panic when computing...but don't care about result |
150 | | assert_eq!(fast_version, baseline_version); |
151 | | } |
152 | | } |
153 | | } |
154 | | pub fn approx_eq(a: f64, b: f64, tol: f64) { |
155 | | let mut t0 = a - b; |
156 | | let mut t1 = b - a; |
157 | | if t0 < 0.0 { |
158 | | t0 = -t0; |
159 | | } |
160 | | if t1 < 0.0 { |
161 | | t1 = -t1; |
162 | | } |
163 | | if (!(t1 < tol)) { |
164 | | assert_eq!(a, b); |
165 | | } |
166 | | if (!(t0 < tol)) { |
167 | | assert_eq!(a, b); |
168 | | } |
169 | | } |
170 | | #[test] |
171 | | fn fast_log2_works() { |
172 | | let examples = [ |
173 | | 4u64, |
174 | | 254, |
175 | | 256, |
176 | | 1428, |
177 | | 25412509, |
178 | | 21350891256, |
179 | | 65536, |
180 | | 1258912591, |
181 | | 60968101, |
182 | | 1, |
183 | | 12589125190825, |
184 | | 105912059215091, |
185 | | 0, |
186 | | ]; |
187 | | let tol = [ |
188 | | 0.00001, 0.0001, 0.0001, 0.005, 0.007, 0.008, 0.01, 0.01, 0.01, 0.000001, 0.01, 0.01, |
189 | | 0.0001, |
190 | | ]; |
191 | | for (index, example) in examples.iter().enumerate() { |
192 | | let fast_version = super::FastLog2(*example); |
193 | | if *example != 0 { |
194 | | // make sure we don't panic when computing...but don't care about result |
195 | | let baseline_version = (*example as f64).log2(); |
196 | | approx_eq(fast_version as f64, baseline_version, tol[index]); |
197 | | } else { |
198 | | //assert_eq!(fast_version as f64, 0.0 as f64); |
199 | | } |
200 | | } |
201 | | } |
202 | | } |