/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 | 6.83G | pub fn FastLog2u16(v: u16) -> floatX { |
14 | 6.83G | logs_16[v as usize] |
15 | 6.83G | } |
16 | | |
17 | | #[cfg(feature = "std")] |
18 | | #[inline(always)] |
19 | 557M | pub fn FastLog2(v: u64) -> floatX { |
20 | 557M | if v < 256 { |
21 | 515M | logs_8[v as usize] |
22 | | } else { |
23 | 41.7M | (v as f32).log2() as floatX |
24 | | } |
25 | 557M | } |
26 | | |
27 | | #[cfg(not(feature = "std"))] |
28 | | #[inline(always)] |
29 | | pub fn FastLog2(v: u64) -> floatX { |
30 | | if v < 256 { |
31 | | logs_8[v as usize] |
32 | | } else { |
33 | | FastLog2u64(v) |
34 | | } |
35 | | } |
36 | | |
37 | | #[cfg(feature = "std")] |
38 | | #[inline(always)] |
39 | 389M | pub fn FastLog2f64(v: u64) -> floatX { |
40 | 389M | if v < 256 { |
41 | 98.8M | logs_8[v as usize] |
42 | | } else { |
43 | 290M | (v as floatX).log2() |
44 | | } |
45 | 389M | } |
46 | | |
47 | | #[cfg(not(feature = "std"))] |
48 | | #[inline(always)] |
49 | | pub fn FastLog2f64(v: u64) -> floatX { |
50 | | FastLog2(v) as floatX |
51 | | } |
52 | | |
53 | | #[inline] |
54 | 0 | pub fn FastLog2u64(v: u64) -> floatX { |
55 | 0 | let bsr_8 = 56i8 - v.leading_zeros() as i8; |
56 | 0 | let offset = bsr_8 & -((bsr_8 >= 0) as i8); |
57 | 0 | (offset as floatX) + logs_8[(v >> offset) as usize] |
58 | 0 | } |
59 | | |
60 | | #[inline(always)] |
61 | 0 | pub fn FastLog2u32(v: i32) -> floatX { |
62 | 0 | let bsr_8 = 24i8 - 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 xFastLog2u16(v: u16) -> floatX { |
69 | 0 | let bsr_8 = 8i8 - 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 | | #[cfg(feature = "std")] |
75 | | #[inline(always)] |
76 | 0 | pub fn FastPow2(v: floatX) -> floatX { |
77 | 0 | (2 as floatX).powf(v) |
78 | 0 | } |
79 | | |
80 | | #[cfg(not(feature = "std"))] |
81 | | #[inline(always)] |
82 | | pub fn FastPow2(v: floatX) -> floatX { |
83 | | assert!(v >= 0 as floatX); |
84 | | let round_down = v as i32; |
85 | | let remainder = v - round_down as floatX; |
86 | | let mut x = 1 as floatX; |
87 | | // (1 + (x/n) * ln2) ^ n |
88 | | // let n = 8 |
89 | | x += remainder * (0.693147180559945309417232121458 / 256.0) as floatX; |
90 | | x *= x; |
91 | | x *= x; |
92 | | x *= x; |
93 | | x *= x; |
94 | | x *= x; |
95 | | x *= x; |
96 | | x *= x; |
97 | | x *= x; |
98 | | |
99 | | (1 << round_down) as floatX * x |
100 | | } |
101 | | |
102 | | #[inline(always)] |
103 | 4.43G | pub fn Log2FloorNonZero(v: u64) -> u32 { |
104 | 4.43G | 63u32 ^ v.leading_zeros() |
105 | 4.43G | } |
106 | | |
107 | | #[cfg(test)] |
108 | | mod test { |
109 | | fn baseline_log2_floor_non_zero(mut n: u64) -> u32 { |
110 | | let mut result: u32 = 0; |
111 | | while { |
112 | | n >>= 1i32; |
113 | | n |
114 | | } != 0 |
115 | | { |
116 | | result = result.wrapping_add(1); |
117 | | } |
118 | | result |
119 | | } |
120 | | |
121 | | #[test] |
122 | | fn log2floor_non_zero_works() { |
123 | | let examples = [ |
124 | | 4u64, |
125 | | 254, |
126 | | 256, |
127 | | 1428, |
128 | | 25412509, |
129 | | 21350891256, |
130 | | 65536, |
131 | | 1258912591, |
132 | | 60968101, |
133 | | 1, |
134 | | 12589125190825, |
135 | | 105912059215091, |
136 | | 0, |
137 | | ]; |
138 | | for example in examples.iter() { |
139 | | let fast_version = super::Log2FloorNonZero(*example); |
140 | | let baseline_version = baseline_log2_floor_non_zero(*example); |
141 | | if *example != 0 { |
142 | | // make sure we don't panic when computing...but don't care about result |
143 | | assert_eq!(fast_version, baseline_version); |
144 | | } |
145 | | } |
146 | | } |
147 | | pub fn approx_eq(a: f64, b: f64, tol: f64) { |
148 | | let mut t0 = a - b; |
149 | | let mut t1 = b - a; |
150 | | if t0 < 0.0 { |
151 | | t0 = -t0; |
152 | | } |
153 | | if t1 < 0.0 { |
154 | | t1 = -t1; |
155 | | } |
156 | | if (!(t1 < tol)) { |
157 | | assert_eq!(a, b); |
158 | | } |
159 | | if (!(t0 < tol)) { |
160 | | assert_eq!(a, b); |
161 | | } |
162 | | } |
163 | | #[test] |
164 | | fn fast_log2_works() { |
165 | | let examples = [ |
166 | | 4u64, |
167 | | 254, |
168 | | 256, |
169 | | 1428, |
170 | | 25412509, |
171 | | 21350891256, |
172 | | 65536, |
173 | | 1258912591, |
174 | | 60968101, |
175 | | 1, |
176 | | 12589125190825, |
177 | | 105912059215091, |
178 | | 0, |
179 | | ]; |
180 | | let tol = [ |
181 | | 0.00001, 0.0001, 0.0001, 0.005, 0.007, 0.008, 0.01, 0.01, 0.01, 0.000001, 0.01, 0.01, |
182 | | 0.0001, |
183 | | ]; |
184 | | for (index, example) in examples.iter().enumerate() { |
185 | | let fast_version = super::FastLog2(*example); |
186 | | if *example != 0 { |
187 | | // make sure we don't panic when computing...but don't care about result |
188 | | let baseline_version = (*example as f64).log2(); |
189 | | approx_eq(fast_version as f64, baseline_version, tol[index]); |
190 | | } else { |
191 | | //assert_eq!(fast_version as f64, 0.0 as f64); |
192 | | } |
193 | | } |
194 | | } |
195 | | } |