1use crate::frame::mmm::*;
2use std::hash::{Hash, Hasher};
3use std::ops::Mul;
4use tract_data::prelude::f16;
5
6#[derive(Debug, Clone, Copy, PartialEq)]
7pub struct Scaler {
8 pub scale: f32,
9 pub mult: Option<i32>,
10 pub shift: isize,
11 pub policy: RoundingPolicy,
12}
13
14impl Eq for Scaler {}
15
16#[allow(clippy::derived_hash_with_manual_eq)]
17impl Hash for Scaler {
18 fn hash<H>(&self, state: &mut H)
19 where
20 H: Hasher,
21 {
22 Hash::hash(&self.scale.to_bits(), state)
23 }
24}
25
26impl Scaler {
27 pub fn new(scale: f32, policy: RoundingPolicy) -> Self {
28 let (mult, shift) = Self::convert_scale_to_mult_shift(scale);
29 Self { scale, mult, shift, policy }
30 }
31
32 pub fn as_fused_spec(&self) -> FusedSpec {
33 if let Some(multiplier) = self.mult {
34 FusedSpec::QScale(self.shift, self.policy, multiplier)
35 } else if self.shift > 0 {
36 FusedSpec::RoundingShiftRight(self.shift as usize, self.policy)
37 } else {
38 FusedSpec::ShiftLeft((-self.shift) as usize)
39 }
40 }
41
42 pub fn from_fuse_params(shift: isize, policy: RoundingPolicy, mult: i32) -> Self {
44 let scale = mult as f32 * 2f32.powi(-(31 + shift as i32));
45 Self { scale, mult: Some(mult), shift, policy }
46 }
47
48 #[inline]
49 fn convert_scale_to_mult_shift(scale: f32) -> (Option<i32>, isize) {
52 if scale == 0.0 {
54 return (None, 0);
55 }
56
57 let scale_bits = scale.to_bits();
61
62 let current_exponent = (scale_bits >> 23) & 0xff;
64
65 let partial_frac = scale_bits & 0x007fffff;
69
70 if partial_frac == 0 {
71 let shift = 127 - current_exponent as isize;
72 (None, shift)
73 } else {
74 let frac = partial_frac | 0x800000;
77
78 let half_frac = (frac << 7) as i32;
84
85 let shift = 127 - current_exponent as isize - 1;
88 (Some(half_frac), shift)
89 }
90 }
91}
92
93impl Mul<f16> for Scaler {
94 type Output = f16;
95
96 #[inline]
97 fn mul(self, rhs: f16) -> Self::Output {
98 f16::from_f32(self.scale) * rhs
99 }
100}
101
102impl Mul<f32> for Scaler {
103 type Output = f32;
104
105 #[inline]
106 fn mul(self, rhs: f32) -> Self::Output {
107 self.scale * rhs
108 }
109}
110
111impl Mul<f64> for Scaler {
112 type Output = f64;
113
114 #[inline]
115 fn mul(self, rhs: f64) -> Self::Output {
116 self.scale as f64 * rhs
117 }
118}
119
120impl Mul<Scaler> for f16 {
121 type Output = f16;
122
123 #[inline]
124 fn mul(self, rhs: Scaler) -> Self::Output {
125 rhs * self
126 }
127}
128
129impl Mul<Scaler> for f32 {
130 type Output = f32;
131
132 #[inline]
133 fn mul(self, rhs: Scaler) -> Self::Output {
134 rhs * self
135 }
136}
137
138impl Mul<Scaler> for f64 {
139 type Output = f64;
140
141 #[inline]
142 fn mul(self, rhs: Scaler) -> Self::Output {
143 rhs * self
144 }
145}
146
147impl Mul<i32> for Scaler {
148 type Output = i32;
149
150 #[inline]
151 fn mul(self, rhs: i32) -> Self::Output {
152 let (val, shift) = if let Some(multiplier) = self.mult {
153 (multiplier as i64 * rhs as i64, self.shift + 31)
154 } else {
155 (rhs as i64, self.shift)
156 };
157
158 use RoundingPolicy::*;
160 if shift > 0 {
161 let half: i64 = 1 << (shift - 1);
162 let nudge: i64 = match self.policy {
163 Zero => -1,
164 MinusInf => -((val >= 0) as i64),
165 PlusInf => -((val <= 0) as i64),
166 Away => 0,
167 Even => ((val.abs() >> shift) & 0x1) - 1,
168 Odd => -((val.abs() >> shift) & 0x1),
169 _ => panic!(),
170 };
171
172 (val.signum() * ((val.abs() + half + nudge) >> shift)) as i32
173 } else {
174 (val << -shift) as i32
175 }
176 }
177}
178
179impl Mul<Scaler> for i32 {
180 type Output = i32;
181
182 #[inline]
183 fn mul(self, rhs: Scaler) -> Self::Output {
184 rhs * self
185 }
186}
187
188pub trait ScaleShiftAndRound {
189 fn q_scale(self, scaler: Scaler) -> Self;
190 fn q_shl(self, shift: usize) -> Self;
191 fn q_shr(self, shift: usize, rp: RoundingPolicy) -> Self;
192}
193
194impl ScaleShiftAndRound for f64 {
195 fn q_scale(self, scaler: Scaler) -> Self {
196 self * scaler
197 }
198 fn q_shl(self, shift: usize) -> Self {
199 self * 2f64.powi(shift as i32)
200 }
201 fn q_shr(self, shift: usize, _rp: RoundingPolicy) -> Self {
202 self * 2f64.powi(-(shift as i32))
203 }
204}
205
206impl ScaleShiftAndRound for f32 {
207 fn q_scale(self, scaler: Scaler) -> Self {
208 self * scaler
209 }
210 fn q_shl(self, shift: usize) -> Self {
211 self * 2f32.powi(shift as i32)
212 }
213 fn q_shr(self, shift: usize, _rp: RoundingPolicy) -> Self {
214 self * 2f32.powi(-(shift as i32))
215 }
216}
217
218impl ScaleShiftAndRound for f16 {
219 fn q_scale(self, scaler: Scaler) -> Self {
220 self * scaler
221 }
222 fn q_shl(self, shift: usize) -> Self {
223 self * f16::from_f32(2f32.powi(shift as i32))
224 }
225 fn q_shr(self, shift: usize, _rp: RoundingPolicy) -> Self {
226 self * f16::from_f32(2f32.powi(-(shift as i32)))
227 }
228}
229
230impl ScaleShiftAndRound for i32 {
231 fn q_scale(self, scaler: Scaler) -> Self {
232 self * scaler
233 }
234 fn q_shr(self, shift: usize, rp: RoundingPolicy) -> Self {
235 use RoundingPolicy::*;
236 let half: i32 = 1 << (shift - 1);
237 let nudge: i32 = match rp {
238 Zero => -1,
239 MinusInf => -((self >= 0) as i32),
240 PlusInf => -((self <= 0) as i32),
241 Away => 0,
242 Even => ((self.abs() >> shift) & 0x1) - 1,
243 Odd => -((self.abs() >> shift) & 0x1),
244 _ => panic!(),
245 };
246 self.signum() * ((self.abs() + half + nudge) >> shift)
247 }
248 fn q_shl(self, shift: usize) -> Self {
249 self << shift
250 }
251}
252
253#[cfg(test)]
257mod test {
258 use super::RoundingPolicy::*;
259 use super::*;
260
261 #[test]
262 fn test_scale_rounding_f32() {
263 assert_eq!(0f32.q_scale(Scaler::new(0.5, Zero)), 0.0);
264 assert_eq!(1f32.q_scale(Scaler::new(0.5, Zero)), 0.5);
265 assert_eq!(2f32.q_scale(Scaler::new(0.5, Zero)), 1.0);
266 assert_eq!(3f32.q_scale(Scaler::new(0.5, Zero)), 1.5);
267 assert_eq!((-1f32).q_scale(Scaler::new(0.5, Zero)), -0.5);
268 assert_eq!((-2f32).q_scale(Scaler::new(0.5, Zero)), -1.0);
269 assert_eq!((-3f32).q_scale(Scaler::new(0.5, Zero)), -1.5);
270 }
271
272 #[test]
273 fn test_shift_rounding_zero() {
274 assert_eq!(0i32.q_shr(1, Zero), 0);
275 assert_eq!(1i32.q_shr(1, Zero), 0);
276 assert_eq!(2i32.q_shr(1, Zero), 1);
277 assert_eq!(3i32.q_shr(1, Zero), 1);
278 assert_eq!(0i32.q_shr(2, Zero), 0);
279 assert_eq!(1i32.q_shr(2, Zero), 0);
280 assert_eq!(2i32.q_shr(2, Zero), 0);
281 assert_eq!(3i32.q_shr(2, Zero), 1);
282 assert_eq!(4i32.q_shr(2, Zero), 1);
283 assert_eq!(5i32.q_shr(2, Zero), 1);
284 assert_eq!(6i32.q_shr(2, Zero), 1);
285 assert_eq!((-1i32).q_shr(2, Zero), 0);
286 assert_eq!((-2i32).q_shr(2, Zero), 0);
287 assert_eq!((-3i32).q_shr(2, Zero), -1);
288 assert_eq!((-4i32).q_shr(2, Zero), -1);
289 assert_eq!((-5i32).q_shr(2, Zero), -1);
290 assert_eq!((-6i32).q_shr(2, Zero), -1);
291 }
292
293 #[test]
294 fn test_scale_rounding_zero() {
295 assert_eq!(0i32.q_scale(Scaler::new(0.5, Zero)), 0);
296 assert_eq!(1i32.q_scale(Scaler::new(0.5, Zero)), 0);
297 assert_eq!(2i32.q_scale(Scaler::new(0.5, Zero)), 1);
298 assert_eq!(3i32.q_scale(Scaler::new(0.5, Zero)), 1);
299 assert_eq!((-1i32).q_scale(Scaler::new(0.5, Zero)), 0);
300 assert_eq!((-2i32).q_scale(Scaler::new(0.5, Zero)), -1);
301 assert_eq!((-3i32).q_scale(Scaler::new(0.5, Zero)), -1);
302 assert_eq!(2i32.q_scale(Scaler::new(0.25, Zero)), 0);
303 assert_eq!(3i32.q_scale(Scaler::new(0.25, Zero)), 1);
304 assert_eq!(4i32.q_scale(Scaler::new(0.25, Zero)), 1);
305 assert_eq!(5i32.q_scale(Scaler::new(0.25, Zero)), 1);
306 assert_eq!(6i32.q_scale(Scaler::new(0.25, Zero)), 1);
307 assert_eq!((-2i32).q_scale(Scaler::new(0.25, Zero)), 0);
308 assert_eq!((-3i32).q_scale(Scaler::new(0.25, Zero)), -1);
309 assert_eq!((-4i32).q_scale(Scaler::new(0.25, Zero)), -1);
310 assert_eq!((-5i32).q_scale(Scaler::new(0.25, Zero)), -1);
311 assert_eq!((-6i32).q_scale(Scaler::new(0.25, Zero)), -1);
312 }
313
314 #[test]
315 fn test_shift_rounding_away() {
316 assert_eq!(0i32.q_shr(1, Away), 0);
317 assert_eq!(1i32.q_shr(1, Away), 1);
318 assert_eq!(2i32.q_shr(1, Away), 1);
319 assert_eq!(3i32.q_shr(1, Away), 2);
320 assert_eq!(0i32.q_shr(2, Away), 0);
321 assert_eq!(1i32.q_shr(2, Away), 0);
322 assert_eq!(2i32.q_shr(2, Away), 1);
323 assert_eq!(3i32.q_shr(2, Away), 1);
324 assert_eq!(4i32.q_shr(2, Away), 1);
325 assert_eq!(5i32.q_shr(2, Away), 1);
326 assert_eq!(6i32.q_shr(2, Away), 2);
327 assert_eq!((-1i32).q_shr(2, Away), 0);
328 assert_eq!((-2i32).q_shr(2, Away), -1);
329 assert_eq!((-3i32).q_shr(2, Away), -1);
330 assert_eq!((-4i32).q_shr(2, Away), -1);
331 assert_eq!((-5i32).q_shr(2, Away), -1);
332 assert_eq!((-6i32).q_shr(2, Away), -2);
333 }
334
335 #[test]
336 fn test_scale_rounding_away() {
337 assert_eq!(0i32.q_scale(Scaler::new(0.5, Away)), 0);
338 assert_eq!(1i32.q_scale(Scaler::new(0.5, Away)), 1);
339 assert_eq!(2i32.q_scale(Scaler::new(0.5, Away)), 1);
340 assert_eq!(3i32.q_scale(Scaler::new(0.5, Away)), 2);
341 assert_eq!((-1i32).q_scale(Scaler::new(0.5, Away)), -1);
342 assert_eq!((-2i32).q_scale(Scaler::new(0.5, Away)), -1);
343 assert_eq!((-3i32).q_scale(Scaler::new(0.5, Away)), -2);
344 assert_eq!(2i32.q_scale(Scaler::new(0.25, Away)), 1);
345 assert_eq!(3i32.q_scale(Scaler::new(0.25, Away)), 1);
346 assert_eq!(4i32.q_scale(Scaler::new(0.25, Away)), 1);
347 assert_eq!(5i32.q_scale(Scaler::new(0.25, Away)), 1);
348 assert_eq!(6i32.q_scale(Scaler::new(0.25, Away)), 2);
349 assert_eq!((-2i32).q_scale(Scaler::new(0.25, Away)), -1);
350 assert_eq!((-3i32).q_scale(Scaler::new(0.25, Away)), -1);
351 assert_eq!((-4i32).q_scale(Scaler::new(0.25, Away)), -1);
352 assert_eq!((-5i32).q_scale(Scaler::new(0.25, Away)), -1);
353 assert_eq!((-6i32).q_scale(Scaler::new(0.25, Away)), -2);
354 }
355
356 #[test]
357 fn test_shift_rounding_plus_inf() {
358 assert_eq!(0i32.q_shr(1, PlusInf), 0);
359 assert_eq!(1i32.q_shr(1, PlusInf), 1);
360 assert_eq!(2i32.q_shr(1, PlusInf), 1);
361 assert_eq!(3i32.q_shr(1, PlusInf), 2);
362 assert_eq!(0i32.q_shr(2, PlusInf), 0);
363 assert_eq!(1i32.q_shr(2, PlusInf), 0);
364 assert_eq!(2i32.q_shr(2, PlusInf), 1);
365 assert_eq!(3i32.q_shr(2, PlusInf), 1);
366 assert_eq!(4i32.q_shr(2, PlusInf), 1);
367 assert_eq!(5i32.q_shr(2, PlusInf), 1);
368 assert_eq!(6i32.q_shr(2, PlusInf), 2);
369 assert_eq!((-1i32).q_shr(2, PlusInf), 0);
370 assert_eq!((-2i32).q_shr(2, PlusInf), 0);
371 assert_eq!((-3i32).q_shr(2, PlusInf), -1);
372 assert_eq!((-4i32).q_shr(2, PlusInf), -1);
373 assert_eq!((-5i32).q_shr(2, PlusInf), -1);
374 assert_eq!((-6i32).q_shr(2, PlusInf), -1);
375 }
376
377 #[test]
378 fn test_scale_rounding_plus_inf() {
379 assert_eq!(0i32.q_scale(Scaler::new(0.5, PlusInf)), 0);
380 assert_eq!(1i32.q_scale(Scaler::new(0.5, PlusInf)), 1);
381 assert_eq!(2i32.q_scale(Scaler::new(0.5, PlusInf)), 1);
382 assert_eq!(3i32.q_scale(Scaler::new(0.5, PlusInf)), 2);
383 assert_eq!((-1i32).q_scale(Scaler::new(0.5, PlusInf)), 0);
384 assert_eq!((-2i32).q_scale(Scaler::new(0.5, PlusInf)), -1);
385 assert_eq!((-3i32).q_scale(Scaler::new(0.5, PlusInf)), -1);
386 assert_eq!(2i32.q_scale(Scaler::new(0.25, PlusInf)), 1);
387 assert_eq!(3i32.q_scale(Scaler::new(0.25, PlusInf)), 1);
388 assert_eq!(4i32.q_scale(Scaler::new(0.25, PlusInf)), 1);
389 assert_eq!(5i32.q_scale(Scaler::new(0.25, PlusInf)), 1);
390 assert_eq!(6i32.q_scale(Scaler::new(0.25, PlusInf)), 2);
391 assert_eq!((-2i32).q_scale(Scaler::new(0.25, PlusInf)), 0);
392 assert_eq!((-3i32).q_scale(Scaler::new(0.25, PlusInf)), -1);
393 assert_eq!((-4i32).q_scale(Scaler::new(0.25, PlusInf)), -1);
394 assert_eq!((-5i32).q_scale(Scaler::new(0.25, PlusInf)), -1);
395 assert_eq!((-6i32).q_scale(Scaler::new(0.25, PlusInf)), -1);
396 }
397
398 #[test]
399 fn test_shift_rounding_minus_inf() {
400 assert_eq!(0i32.q_shr(1, MinusInf), 0);
401 assert_eq!(1i32.q_shr(1, MinusInf), 0);
402 assert_eq!(2i32.q_shr(1, MinusInf), 1);
403 assert_eq!(3i32.q_shr(1, MinusInf), 1);
404 assert_eq!(0i32.q_shr(2, MinusInf), 0);
405 assert_eq!(1i32.q_shr(2, MinusInf), 0);
406 assert_eq!(2i32.q_shr(2, MinusInf), 0);
407 assert_eq!(3i32.q_shr(2, MinusInf), 1);
408 assert_eq!(4i32.q_shr(2, MinusInf), 1);
409 assert_eq!(5i32.q_shr(2, MinusInf), 1);
410 assert_eq!(6i32.q_shr(2, MinusInf), 1);
411 assert_eq!((-1i32).q_shr(2, MinusInf), 0);
412 assert_eq!((-2i32).q_shr(2, MinusInf), -1);
413 assert_eq!((-3i32).q_shr(2, MinusInf), -1);
414 assert_eq!((-4i32).q_shr(2, MinusInf), -1);
415 assert_eq!((-5i32).q_shr(2, MinusInf), -1);
416 assert_eq!((-6i32).q_shr(2, MinusInf), -2);
417 }
418
419 #[test]
420 fn test_scale_rounding_minus_inf() {
421 assert_eq!(0i32.q_scale(Scaler::new(0.5, MinusInf)), 0);
422 assert_eq!(1i32.q_scale(Scaler::new(0.5, MinusInf)), 0);
423 assert_eq!(2i32.q_scale(Scaler::new(0.5, MinusInf)), 1);
424 assert_eq!(3i32.q_scale(Scaler::new(0.5, MinusInf)), 1);
425 assert_eq!((-1i32).q_scale(Scaler::new(0.5, MinusInf)), -1);
426 assert_eq!((-2i32).q_scale(Scaler::new(0.5, MinusInf)), -1);
427 assert_eq!((-3i32).q_scale(Scaler::new(0.5, MinusInf)), -2);
428 assert_eq!(2i32.q_scale(Scaler::new(0.25, MinusInf)), 0);
429 assert_eq!(3i32.q_scale(Scaler::new(0.25, MinusInf)), 1);
430 assert_eq!(4i32.q_scale(Scaler::new(0.25, MinusInf)), 1);
431 assert_eq!(5i32.q_scale(Scaler::new(0.25, MinusInf)), 1);
432 assert_eq!(6i32.q_scale(Scaler::new(0.25, MinusInf)), 1);
433 assert_eq!((-2i32).q_scale(Scaler::new(0.25, MinusInf)), -1);
434 assert_eq!((-3i32).q_scale(Scaler::new(0.25, MinusInf)), -1);
435 assert_eq!((-4i32).q_scale(Scaler::new(0.25, MinusInf)), -1);
436 assert_eq!((-5i32).q_scale(Scaler::new(0.25, MinusInf)), -1);
437 assert_eq!((-6i32).q_scale(Scaler::new(0.25, MinusInf)), -2);
438 }
440
441 #[test]
442 fn test_shift_rounding_even() {
443 assert_eq!(0i32.q_shr(1, Even), 0);
444 assert_eq!(1i32.q_shr(1, Even), 0);
445 assert_eq!(2i32.q_shr(1, Even), 1);
446 assert_eq!(3i32.q_shr(1, Even), 2);
447 assert_eq!(0i32.q_shr(2, Even), 0);
448 assert_eq!(1i32.q_shr(2, Even), 0);
449 assert_eq!(2i32.q_shr(2, Even), 0);
450 assert_eq!(3i32.q_shr(2, Even), 1);
451 assert_eq!(4i32.q_shr(2, Even), 1);
452 assert_eq!(5i32.q_shr(2, Even), 1);
453 assert_eq!(6i32.q_shr(2, Even), 2);
454 assert_eq!((-1i32).q_shr(2, Even), 0);
455 assert_eq!((-2i32).q_shr(2, Even), 0);
456 assert_eq!((-3i32).q_shr(2, Even), -1);
457 assert_eq!((-4i32).q_shr(2, Even), -1);
458 assert_eq!((-5i32).q_shr(2, Even), -1);
459 assert_eq!((-6i32).q_shr(2, Even), -2);
460 }
461
462 #[test]
463 fn test_scale_rounding_even() {
464 assert_eq!(0i32.q_scale(Scaler::new(0.5, Even)), 0);
465 assert_eq!(1i32.q_scale(Scaler::new(0.5, Even)), 0);
466 assert_eq!(2i32.q_scale(Scaler::new(0.5, Even)), 1);
467 assert_eq!(3i32.q_scale(Scaler::new(0.5, Even)), 2);
468 assert_eq!((-1i32).q_scale(Scaler::new(0.5, Even)), 0);
469 assert_eq!((-2i32).q_scale(Scaler::new(0.5, Even)), -1);
470 assert_eq!((-3i32).q_scale(Scaler::new(0.5, Even)), -2);
471 assert_eq!(2i32.q_scale(Scaler::new(0.25, Even)), 0);
472 assert_eq!(3i32.q_scale(Scaler::new(0.25, Even)), 1);
473 assert_eq!(4i32.q_scale(Scaler::new(0.25, Even)), 1);
474 assert_eq!(5i32.q_scale(Scaler::new(0.25, Even)), 1);
475 assert_eq!(6i32.q_scale(Scaler::new(0.25, Even)), 2);
476 assert_eq!((-2i32).q_scale(Scaler::new(0.25, Even)), 0);
477 assert_eq!((-3i32).q_scale(Scaler::new(0.25, Even)), -1);
478 assert_eq!((-4i32).q_scale(Scaler::new(0.25, Even)), -1);
479 assert_eq!((-5i32).q_scale(Scaler::new(0.25, Even)), -1);
480 assert_eq!((-6i32).q_scale(Scaler::new(0.25, Even)), -2);
481 }
482
483 #[test]
484 fn test_shift_rounding_odd() {
485 assert_eq!(0i32.q_shr(1, Odd), 0);
486 assert_eq!(1i32.q_shr(1, Odd), 1);
487 assert_eq!(2i32.q_shr(1, Odd), 1);
488 assert_eq!(3i32.q_shr(1, Odd), 1);
489 assert_eq!(0i32.q_shr(2, Odd), 0);
490 assert_eq!(1i32.q_shr(2, Odd), 0);
491 assert_eq!(2i32.q_shr(2, Odd), 1);
492 assert_eq!(3i32.q_shr(2, Odd), 1);
493 assert_eq!(4i32.q_shr(2, Odd), 1);
494 assert_eq!(5i32.q_shr(2, Odd), 1);
495 assert_eq!(6i32.q_shr(2, Odd), 1);
496 assert_eq!((-1i32).q_shr(2, Odd), 0);
497 assert_eq!((-2i32).q_shr(2, Odd), -1);
498 assert_eq!((-3i32).q_shr(2, Odd), -1);
499 assert_eq!((-4i32).q_shr(2, Odd), -1);
500 assert_eq!((-5i32).q_shr(2, Odd), -1);
501 assert_eq!((-6i32).q_shr(2, Odd), -1);
502 }
503
504 #[test]
505 fn test_scale_rounding_odd() {
506 assert_eq!(0i32.q_scale(Scaler::new(0.5, Odd)), 0);
507 assert_eq!(1i32.q_scale(Scaler::new(0.5, Odd)), 1);
508 assert_eq!(2i32.q_scale(Scaler::new(0.5, Odd)), 1);
509 assert_eq!(3i32.q_scale(Scaler::new(0.5, Odd)), 1);
510 assert_eq!((-1i32).q_scale(Scaler::new(0.5, Odd)), -1);
511 assert_eq!((-2i32).q_scale(Scaler::new(0.5, Odd)), -1);
512 assert_eq!((-3i32).q_scale(Scaler::new(0.5, Odd)), -1);
513 assert_eq!(2i32.q_scale(Scaler::new(0.25, Odd)), 1);
514 assert_eq!(3i32.q_scale(Scaler::new(0.25, Odd)), 1);
515 assert_eq!(4i32.q_scale(Scaler::new(0.25, Odd)), 1);
516 assert_eq!(5i32.q_scale(Scaler::new(0.25, Odd)), 1);
517 assert_eq!(6i32.q_scale(Scaler::new(0.25, Odd)), 1);
518 assert_eq!((-2i32).q_scale(Scaler::new(0.25, Odd)), -1);
519 assert_eq!((-3i32).q_scale(Scaler::new(0.25, Odd)), -1);
520 assert_eq!((-4i32).q_scale(Scaler::new(0.25, Odd)), -1);
521 assert_eq!((-5i32).q_scale(Scaler::new(0.25, Odd)), -1);
522 assert_eq!((-6i32).q_scale(Scaler::new(0.25, Odd)), -1);
523 }
524}