substrate_fixed/
arith.rs

1// Copyright © 2018–2019 Trevor Spiteri
2
3// This library is free software: you can redistribute it and/or
4// modify it under the terms of either
5//
6//   * the Apache License, Version 2.0 or
7//   * the MIT License
8//
9// at your option.
10//
11// You should have recieved copies of the Apache License and the MIT
12// License along with the library. If not, see
13// <https://www.apache.org/licenses/LICENSE-2.0> and
14// <https://opensource.org/licenses/MIT>.
15
16use crate::{
17    helpers::IntHelper,
18    traits::ToFixed,
19    types::extra::{LeEqU128, LeEqU16, LeEqU32, LeEqU64, LeEqU8},
20    wide_div::WideDivRem,
21    FixedI128, FixedI16, FixedI32, FixedI64, FixedI8, FixedU128, FixedU16, FixedU32, FixedU64,
22    FixedU8,
23};
24use core::{
25    iter::{Product, Sum},
26    ops::{
27        Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div,
28        DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub,
29        SubAssign,
30    },
31};
32
33macro_rules! refs {
34    (impl $Imp:ident for $Fixed:ident$(($LeEqU:ident))* { $method:ident }) => {
35        impl<'a, Frac $(: $LeEqU)*> $Imp<$Fixed<Frac>> for &'a $Fixed<Frac> {
36            type Output = $Fixed<Frac>;
37            #[inline]
38            fn $method(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
39                (*self).$method(rhs)
40            }
41        }
42
43        impl<'a, Frac $(: $LeEqU)*> $Imp<&'a $Fixed<Frac>> for $Fixed<Frac> {
44            type Output = $Fixed<Frac>;
45            #[inline]
46            fn $method(self, rhs: &$Fixed<Frac>) -> $Fixed<Frac> {
47                self.$method(*rhs)
48            }
49        }
50
51        impl<'a, 'b, Frac $(: $LeEqU)*> $Imp<&'a $Fixed<Frac>> for &'b $Fixed<Frac> {
52            type Output = $Fixed<Frac>;
53            #[inline]
54            fn $method(self, rhs: &$Fixed<Frac>) -> $Fixed<Frac> {
55                (*self).$method(*rhs)
56            }
57        }
58    };
59
60    (impl $Imp:ident<$Inner:ty> for $Fixed:ident$(($LeEqU:ident))* { $method:ident }) => {
61        impl<'a, Frac $(: $LeEqU)*> $Imp<$Inner> for &'a $Fixed<Frac> {
62            type Output = $Fixed<Frac>;
63            #[inline]
64            fn $method(self, rhs: $Inner) -> $Fixed<Frac> {
65                (*self).$method(rhs)
66            }
67        }
68
69        impl<'a, Frac $(: $LeEqU)*> $Imp<&'a $Inner> for $Fixed<Frac> {
70            type Output = $Fixed<Frac>;
71            #[inline]
72            fn $method(self, rhs: &$Inner) -> $Fixed<Frac> {
73                self.$method(*rhs)
74            }
75        }
76
77        impl<'a, 'b, Frac $(: $LeEqU)*> $Imp<&'a $Inner> for &'b $Fixed<Frac> {
78            type Output = $Fixed<Frac>;
79            #[inline]
80            fn $method(self, rhs: &$Inner) -> $Fixed<Frac> {
81                (*self).$method(*rhs)
82            }
83        }
84    };
85}
86
87macro_rules! refs_assign {
88    (impl $Imp:ident for $Fixed:ident$(($LeEqU:ident))* { $method:ident }) => {
89        impl<'a, Frac $(: $LeEqU)*> $Imp<&'a $Fixed<Frac>> for $Fixed<Frac> {
90            #[inline]
91            fn $method(&mut self, rhs: &$Fixed<Frac>) {
92                self.$method(*rhs);
93            }
94        }
95    };
96
97    (impl $Imp:ident<$Inner:ty> for $Fixed:ident$(($LeEqU:ident))* { $method:ident }) => {
98        impl<'a, Frac $(: $LeEqU)*> $Imp<&'a $Inner> for $Fixed<Frac> {
99            #[inline]
100            fn $method(&mut self, rhs: &$Inner) {
101                self.$method(*rhs);
102            }
103        }
104    };
105}
106
107macro_rules! pass {
108    (impl $Imp:ident for $Fixed:ident { $method:ident }) => {
109        impl<Frac> $Imp<$Fixed<Frac>> for $Fixed<Frac> {
110            type Output = $Fixed<Frac>;
111            #[inline]
112            fn $method(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
113                Self::from_bits(self.to_bits().$method(rhs.to_bits()))
114            }
115        }
116
117        refs! { impl $Imp for $Fixed { $method } }
118    };
119}
120
121macro_rules! pass_assign {
122    (impl $Imp:ident for $Fixed:ident { $method:ident }) => {
123        impl<Frac> $Imp<$Fixed<Frac>> for $Fixed<Frac> {
124            #[inline]
125            fn $method(&mut self, rhs: $Fixed<Frac>) {
126                self.bits.$method(rhs.to_bits())
127            }
128        }
129
130        refs_assign! { impl $Imp for $Fixed { $method } }
131    };
132}
133
134macro_rules! pass_one {
135    (impl $Imp:ident for $Fixed:ident { $method:ident }) => {
136        impl<Frac> $Imp for $Fixed<Frac> {
137            type Output = $Fixed<Frac>;
138            #[inline]
139            fn $method(self) -> $Fixed<Frac> {
140                Self::from_bits(self.to_bits().$method())
141            }
142        }
143
144        impl<'a, Frac> $Imp for &'a $Fixed<Frac> {
145            type Output = $Fixed<Frac>;
146            #[inline]
147            fn $method(self) -> $Fixed<Frac> {
148                (*self).$method()
149            }
150        }
151    };
152}
153
154macro_rules! shift {
155    (impl $Imp:ident < $Rhs:ty > for $Fixed:ident { $method:ident }) => {
156        impl<Frac> $Imp<$Rhs> for $Fixed<Frac> {
157            type Output = $Fixed<Frac>;
158            #[inline]
159            fn $method(self, rhs: $Rhs) -> $Fixed<Frac> {
160                $Fixed::from_bits(self.to_bits().$method(rhs))
161            }
162        }
163
164        impl<'a, Frac> $Imp<$Rhs> for &'a $Fixed<Frac> {
165            type Output = $Fixed<Frac>;
166            #[inline]
167            fn $method(self, rhs: $Rhs) -> $Fixed<Frac> {
168                (*self).$method(rhs)
169            }
170        }
171
172        impl<'a, Frac> $Imp<&'a $Rhs> for $Fixed<Frac> {
173            type Output = $Fixed<Frac>;
174            #[inline]
175            fn $method(self, rhs: &$Rhs) -> $Fixed<Frac> {
176                self.$method(*rhs)
177            }
178        }
179
180        impl<'a, 'b, Frac> $Imp<&'a $Rhs> for &'b $Fixed<Frac> {
181            type Output = $Fixed<Frac>;
182            #[inline]
183            fn $method(self, rhs: &$Rhs) -> $Fixed<Frac> {
184                (*self).$method(*rhs)
185            }
186        }
187    };
188}
189
190macro_rules! shift_assign {
191    (impl $Imp:ident < $Rhs:ty > for $Fixed:ident { $method:ident }) => {
192        impl<Frac> $Imp<$Rhs> for $Fixed<Frac> {
193            #[inline]
194            fn $method(&mut self, rhs: $Rhs) {
195                self.bits.$method(rhs)
196            }
197        }
198
199        impl<'a, Frac> $Imp<&'a $Rhs> for $Fixed<Frac> {
200            #[inline]
201            fn $method(&mut self, rhs: &$Rhs) {
202                self.$method(*rhs)
203            }
204        }
205    };
206}
207
208macro_rules! shift_all {
209    (
210        impl {$Imp:ident, $ImpAssign:ident}<{$($Rhs:ty),*}> for $Fixed:ident
211        { $method:ident, $method_assign:ident }
212    ) => { $(
213        shift! { impl $Imp<$Rhs> for $Fixed { $method } }
214        shift_assign! { impl $ImpAssign<$Rhs> for $Fixed { $method_assign } }
215    )* };
216}
217
218macro_rules! fixed_arith {
219    ($Fixed:ident($Inner:ty, $LeEqU:ident, $bits_count:expr), $Signedness:tt) => {
220        if_signed! {
221            $Signedness; pass_one! { impl Neg for $Fixed { neg } }
222        }
223
224        pass! { impl Add for $Fixed { add } }
225        pass_assign! { impl AddAssign for $Fixed { add_assign } }
226        pass! { impl Sub for $Fixed { sub } }
227        pass_assign! { impl SubAssign for $Fixed { sub_assign } }
228
229        impl<Frac: $LeEqU> Mul<$Fixed<Frac>> for $Fixed<Frac> {
230            type Output = $Fixed<Frac>;
231            #[inline]
232            fn mul(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
233                let (ans, overflow) = self.to_bits().mul_overflow(rhs.to_bits(), Frac::U32);
234                debug_assert!(!overflow, "overflow");
235                Self::from_bits(ans)
236            }
237        }
238
239        refs! { impl Mul for $Fixed($LeEqU) { mul } }
240
241        impl<Frac: $LeEqU> MulAssign<$Fixed<Frac>> for $Fixed<Frac> {
242            #[inline]
243            fn mul_assign(&mut self, rhs: $Fixed<Frac>) {
244                *self = (*self).mul(rhs)
245            }
246        }
247
248        refs_assign! { impl MulAssign for $Fixed($LeEqU) { mul_assign } }
249
250        impl<Frac: $LeEqU> Div<$Fixed<Frac>> for $Fixed<Frac> {
251            type Output = $Fixed<Frac>;
252            #[inline]
253            fn div(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
254                let (ans, overflow) = self.to_bits().div_overflow(rhs.to_bits(), Frac::U32);
255                debug_assert!(!overflow, "overflow");
256                Self::from_bits(ans)
257            }
258        }
259
260        refs! { impl Div for $Fixed($LeEqU) { div } }
261
262        impl<Frac: $LeEqU> DivAssign<$Fixed<Frac>> for $Fixed<Frac> {
263            #[inline]
264            fn div_assign(&mut self, rhs: $Fixed<Frac>) {
265                *self = (*self).div(rhs)
266            }
267        }
268
269        refs_assign! { impl DivAssign for $Fixed($LeEqU) { div_assign } }
270
271        // do not pass! { Rem }, as I::min_value() % I::from(-1) should return 0, not panic
272        impl<Frac> Rem<$Fixed<Frac>> for $Fixed<Frac> {
273            type Output = $Fixed<Frac>;
274            #[inline]
275            fn rem(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
276                self.checked_rem(rhs).expect("division by zero")
277            }
278        }
279
280        refs! { impl Rem for $Fixed { rem } }
281
282        impl<Frac> RemAssign<$Fixed<Frac>> for $Fixed<Frac> {
283            #[inline]
284            fn rem_assign(&mut self, rhs: $Fixed<Frac>) {
285                *self = (*self).rem(rhs)
286            }
287        }
288
289        refs_assign! { impl RemAssign for $Fixed { rem_assign } }
290
291        pass_one! { impl Not for $Fixed { not } }
292        pass! { impl BitAnd for $Fixed { bitand } }
293        pass_assign! { impl BitAndAssign for $Fixed { bitand_assign } }
294        pass! { impl BitOr for $Fixed { bitor } }
295        pass_assign! { impl BitOrAssign for $Fixed { bitor_assign } }
296        pass! { impl BitXor for $Fixed { bitxor } }
297        pass_assign! { impl BitXorAssign for $Fixed { bitxor_assign } }
298
299        impl<Frac: $LeEqU> Mul<$Inner> for $Fixed<Frac> {
300            type Output = $Fixed<Frac>;
301            #[inline]
302            fn mul(self, rhs: $Inner) -> $Fixed<Frac> {
303                Self::from_bits(self.to_bits().mul(rhs))
304            }
305        }
306
307        refs! { impl Mul<$Inner> for $Fixed($LeEqU) { mul } }
308
309        impl<Frac: $LeEqU> MulAssign<$Inner> for $Fixed<Frac> {
310            #[inline]
311            fn mul_assign(&mut self, rhs: $Inner) {
312                *self = (*self).mul(rhs);
313            }
314        }
315
316        refs_assign! { impl MulAssign<$Inner> for $Fixed($LeEqU) { mul_assign } }
317
318        impl<Frac: $LeEqU> Mul<$Fixed<Frac>> for $Inner {
319            type Output = $Fixed<Frac>;
320            #[inline]
321            fn mul(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
322                rhs.mul(self)
323            }
324        }
325
326        impl<'a, Frac: $LeEqU> Mul<&'a $Fixed<Frac>> for $Inner {
327            type Output = $Fixed<Frac>;
328            #[inline]
329            fn mul(self, rhs: &$Fixed<Frac>) -> $Fixed<Frac> {
330                (*rhs).mul(self)
331            }
332        }
333
334        impl<'a, Frac: $LeEqU> Mul<$Fixed<Frac>> for &'a $Inner {
335            type Output = $Fixed<Frac>;
336            #[inline]
337            fn mul(self, rhs: $Fixed<Frac>) -> $Fixed<Frac> {
338                rhs.mul(*self)
339            }
340        }
341
342        impl<'a, 'b, Frac: $LeEqU> Mul<&'a $Fixed<Frac>> for &'b $Inner {
343            type Output = $Fixed<Frac>;
344            #[inline]
345            fn mul(self, rhs: &$Fixed<Frac>) -> $Fixed<Frac> {
346                (*rhs).mul(*self)
347            }
348        }
349
350        impl<Frac: $LeEqU> Div<$Inner> for $Fixed<Frac> {
351            type Output = $Fixed<Frac>;
352            #[inline]
353            fn div(self, rhs: $Inner) -> $Fixed<Frac> {
354                Self::from_bits(self.to_bits().div(rhs))
355            }
356        }
357
358        refs! { impl Div<$Inner> for $Fixed($LeEqU) { div } }
359
360        impl<Frac: $LeEqU> DivAssign<$Inner> for $Fixed<Frac> {
361            #[inline]
362            fn div_assign(&mut self, rhs: $Inner) {
363                *self = (*self).div(rhs);
364            }
365        }
366
367        refs_assign! { impl DivAssign<$Inner> for $Fixed($LeEqU) { div_assign } }
368
369        impl<Frac: $LeEqU> Rem<$Inner> for $Fixed<Frac> {
370            type Output = $Fixed<Frac>;
371            #[inline]
372            fn rem(self, rhs: $Inner) -> $Fixed<Frac> {
373                self.checked_rem_int(rhs).expect("division by zero")
374            }
375        }
376
377        refs! { impl Rem<$Inner> for $Fixed($LeEqU) { rem } }
378
379        impl<Frac: $LeEqU> RemAssign<$Inner> for $Fixed<Frac> {
380            #[inline]
381            fn rem_assign(&mut self, rhs: $Inner) {
382                *self = (*self).rem(rhs);
383            }
384        }
385
386        refs_assign! { impl RemAssign<$Inner> for $Fixed($LeEqU) { rem_assign } }
387
388        shift_all! {
389            impl {Shl, ShlAssign}<{
390                i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize
391            }> for $Fixed {
392                shl, shl_assign
393            }
394        }
395        shift_all! {
396            impl {Shr, ShrAssign}<{
397                i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize
398            }> for $Fixed {
399                shr, shr_assign
400            }
401        }
402
403        impl<Frac> Sum<$Fixed<Frac>> for $Fixed<Frac> {
404            fn sum<I>(iter: I) -> $Fixed<Frac>
405            where
406                I: Iterator<Item = $Fixed<Frac>>,
407            {
408                iter.fold(Self::from_bits(0), Add::add)
409            }
410        }
411
412        impl<'a, Frac: 'a> Sum<&'a $Fixed<Frac>> for $Fixed<Frac> {
413            fn sum<I>(iter: I) -> $Fixed<Frac>
414            where
415                I: Iterator<Item = &'a $Fixed<Frac>>,
416            {
417                iter.fold(Self::from_bits(0), Add::add)
418            }
419        }
420
421        impl<Frac: $LeEqU> Product<$Fixed<Frac>> for $Fixed<Frac> {
422            fn product<I>(mut iter: I) -> $Fixed<Frac>
423            where
424                I: Iterator<Item = $Fixed<Frac>>,
425            {
426                match iter.next() {
427                    None => 1.to_fixed(),
428                    Some(first) => iter.fold(first, Mul::mul),
429                }
430            }
431        }
432
433        impl<'a, Frac: 'a + $LeEqU> Product<&'a $Fixed<Frac>> for $Fixed<Frac> {
434            fn product<I>(mut iter: I) -> $Fixed<Frac>
435            where
436                I: Iterator<Item = &'a $Fixed<Frac>>,
437            {
438                match iter.next() {
439                    None => 1.to_fixed(),
440                    Some(first) => iter.fold(*first, Mul::mul),
441                }
442            }
443        }
444    };
445}
446
447fixed_arith! { FixedU8(u8, LeEqU8, 8), Unsigned }
448fixed_arith! { FixedU16(u16, LeEqU16, 16), Unsigned }
449fixed_arith! { FixedU32(u32, LeEqU32, 32), Unsigned }
450fixed_arith! { FixedU64(u64, LeEqU64, 64), Unsigned }
451fixed_arith! { FixedU128(u128, LeEqU128, 128), Unsigned }
452fixed_arith! { FixedI8(i8, LeEqU8, 8), Signed }
453fixed_arith! { FixedI16(i16, LeEqU16, 16), Signed }
454fixed_arith! { FixedI32(i32, LeEqU32, 32), Signed }
455fixed_arith! { FixedI64(i64, LeEqU64, 64), Signed }
456fixed_arith! { FixedI128(i128, LeEqU128, 128), Signed }
457
458pub(crate) trait MulDivOverflow: Sized {
459    fn mul_overflow(self, rhs: Self, frac_nbits: u32) -> (Self, bool);
460    fn div_overflow(self, rhs: Self, frac_nbits: u32) -> (Self, bool);
461}
462
463macro_rules! mul_div_widen {
464    ($Single:ty, $Double:ty, $Signedness:tt) => {
465        impl MulDivOverflow for $Single {
466            #[inline]
467            fn mul_overflow(self, rhs: $Single, frac_nbits: u32) -> ($Single, bool) {
468                const NBITS: u32 = <$Single>::NBITS;
469                let int_nbits: u32 = NBITS - frac_nbits;
470                let lhs2 = <$Double>::from(self);
471                let rhs2 = <$Double>::from(rhs) << int_nbits;
472                let (prod2, overflow) = lhs2.overflowing_mul(rhs2);
473                ((prod2 >> NBITS) as $Single, overflow)
474            }
475
476            #[inline]
477            fn div_overflow(self, rhs: $Single, frac_nbits: u32) -> ($Single, bool) {
478                const NBITS: u32 = <$Single>::NBITS;
479                let lhs2 = <$Double>::from(self) << frac_nbits;
480                let rhs2 = <$Double>::from(rhs);
481                let quot2 = lhs2 / rhs2;
482                let quot = quot2 as $Single;
483                let overflow = if_signed_unsigned! {
484                    $Signedness,
485                    quot2 >> NBITS != if quot < 0 { -1 } else { 0 },
486                    quot2 >> NBITS != 0
487                };
488                (quot, overflow)
489            }
490        }
491    };
492}
493
494trait FallbackHelper: Sized {
495    type Unsigned;
496    fn hi_lo(self) -> (Self, Self);
497    fn shift_lo_up(self) -> Self;
498    fn shift_lo_up_unsigned(self) -> Self::Unsigned;
499    fn combine_lo_then_shl(self, lo: Self::Unsigned, shift: u32) -> (Self, bool);
500    fn carrying_add(self, other: Self) -> (Self, Self);
501}
502
503impl FallbackHelper for u128 {
504    type Unsigned = u128;
505    #[inline]
506    fn hi_lo(self) -> (u128, u128) {
507        (self >> 64, self & !(!0 << 64))
508    }
509
510    #[inline]
511    fn shift_lo_up(self) -> u128 {
512        debug_assert!(self >> 64 == 0);
513        self << 64
514    }
515
516    #[inline]
517    fn shift_lo_up_unsigned(self) -> u128 {
518        debug_assert!(self >> 64 == 0);
519        self << 64
520    }
521
522    #[inline]
523    fn combine_lo_then_shl(self, lo: u128, shift: u32) -> (u128, bool) {
524        if shift == 128 {
525            (self, false)
526        } else if shift == 0 {
527            (lo, self != 0)
528        } else {
529            let lo = lo >> shift;
530            let hi = self << (128 - shift);
531            (lo | hi, self >> shift != 0)
532        }
533    }
534
535    #[inline]
536    fn carrying_add(self, rhs: u128) -> (u128, u128) {
537        let (sum, overflow) = self.overflowing_add(rhs);
538        let carry = if overflow { 1 } else { 0 };
539        (sum, carry)
540    }
541}
542
543impl FallbackHelper for i128 {
544    type Unsigned = u128;
545    #[inline]
546    fn hi_lo(self) -> (i128, i128) {
547        (self >> 64, self & !(!0 << 64))
548    }
549
550    #[inline]
551    fn shift_lo_up(self) -> i128 {
552        debug_assert!(self >> 64 == 0);
553        self << 64
554    }
555
556    #[inline]
557    fn shift_lo_up_unsigned(self) -> u128 {
558        debug_assert!(self >> 64 == 0);
559        (self << 64) as u128
560    }
561
562    #[inline]
563    fn combine_lo_then_shl(self, lo: u128, shift: u32) -> (i128, bool) {
564        if shift == 128 {
565            (self, false)
566        } else if shift == 0 {
567            let ans = lo as i128;
568            (ans, self != if ans < 0 { -1 } else { 0 })
569        } else {
570            let lo = (lo >> shift) as i128;
571            let hi = self << (128 - shift);
572            let ans = lo | hi;
573            (ans, self >> shift != if ans < 0 { -1 } else { 0 })
574        }
575    }
576
577    #[inline]
578    fn carrying_add(self, rhs: i128) -> (i128, i128) {
579        let (sum, overflow) = self.overflowing_add(rhs);
580        let carry = if overflow {
581            if sum < 0 {
582                1
583            } else {
584                -1
585            }
586        } else {
587            0
588        };
589        (sum, carry)
590    }
591}
592
593macro_rules! mul_div_fallback {
594    ($Single:ty, $Uns:ty, $Signedness:tt) => {
595        impl MulDivOverflow for $Single {
596            #[inline]
597            fn mul_overflow(self, rhs: $Single, frac_nbits: u32) -> ($Single, bool) {
598                if frac_nbits == 0 {
599                    self.overflowing_mul(rhs)
600                } else {
601                    let (lh, ll) = self.hi_lo();
602                    let (rh, rl) = rhs.hi_lo();
603                    let ll_rl = ll.wrapping_mul(rl);
604                    let lh_rl = lh.wrapping_mul(rl);
605                    let ll_rh = ll.wrapping_mul(rh);
606                    let lh_rh = lh.wrapping_mul(rh);
607
608                    let col01 = ll_rl as <$Single as FallbackHelper>::Unsigned;
609                    let (col01_hi, col01_lo) = col01.hi_lo();
610                    let partial_col12 = lh_rl + col01_hi as $Single;
611                    let (col12, carry_col3) = <$Single as FallbackHelper>::carrying_add(partial_col12, ll_rh);
612                    let (col12_hi, col12_lo) = col12.hi_lo();
613                    let ans01 = col12_lo.shift_lo_up_unsigned() + col01_lo;
614                    let ans23 = lh_rh + col12_hi + carry_col3.shift_lo_up();
615                    ans23.combine_lo_then_shl(ans01, frac_nbits)
616                }
617            }
618
619            #[inline]
620            fn div_overflow(self, rhs: $Single, frac_nbits: u32) -> ($Single, bool) {
621                if frac_nbits == 0 {
622                    self.overflowing_div(rhs)
623                } else {
624                    const NBITS: u32 = <$Single>::NBITS;
625                    let lhs2 = (self >> (NBITS - frac_nbits), (self << frac_nbits) as $Uns);
626                    let (quot2, _) = rhs.div_rem_from(lhs2);
627                    let quot = quot2.1 as $Single;
628                    let overflow = if_signed_unsigned! {
629                        $Signedness,
630                        quot2.0 != if quot < 0 { -1 } else { 0 },
631                        quot2.0 != 0
632                    };
633                    (quot, overflow)
634                }
635            }
636        }
637    };
638}
639
640mul_div_widen! { u8, u16, Unsigned }
641mul_div_widen! { u16, u32, Unsigned }
642mul_div_widen! { u32, u64, Unsigned }
643mul_div_widen! { u64, u128, Unsigned }
644mul_div_fallback! { u128, u128, Unsigned }
645mul_div_widen! { i8, i16, Signed }
646mul_div_widen! { i16, i32, Signed }
647mul_div_widen! { i32, i64, Signed }
648mul_div_widen! { i64, i128, Signed }
649mul_div_fallback! { i128, u128, Signed }
650
651#[cfg(test)]
652#[allow(clippy::cognitive_complexity)]
653mod tests {
654    use crate::{types::extra::Unsigned, *};
655
656    #[test]
657    fn fixed_u16() {
658        use crate::types::extra::U7 as Frac;
659        let frac = Frac::U32;
660        let a = 12;
661        let b = 5;
662        for &(a, b) in &[(a, b), (b, a)] {
663            let af = FixedU16::<Frac>::from_num(a);
664            let bf = FixedU16::<Frac>::from_num(b);
665            assert_eq!((af + bf).to_bits(), (a << frac) + (b << frac));
666            if a > b {
667                assert_eq!((af - bf).to_bits(), (a << frac) - (b << frac));
668            }
669            assert_eq!((af * bf).to_bits(), (a << frac) * b);
670            assert_eq!((af / bf).to_bits(), (a << frac) / b);
671            assert_eq!((af % bf).to_bits(), (a << frac) % (b << frac));
672            assert_eq!((af & bf).to_bits(), (a << frac) & (b << frac));
673            assert_eq!((af | bf).to_bits(), (a << frac) | (b << frac));
674            assert_eq!((af ^ bf).to_bits(), (a << frac) ^ (b << frac));
675            assert_eq!((!af).to_bits(), !(a << frac));
676            assert_eq!((af << 4u8).to_bits(), (a << frac) << 4);
677            assert_eq!((af >> 4i128).to_bits(), (a << frac) >> 4);
678            assert_eq!((af * b).to_bits(), (a << frac) * b);
679            assert_eq!((b * af).to_bits(), (a << frac) * b);
680            assert_eq!((af / b).to_bits(), (a << frac) / b);
681            assert_eq!((af % b).to_bits(), (a << frac) % (b << frac));
682        }
683    }
684
685    #[test]
686    fn fixed_i16() {
687        use crate::types::extra::U7 as Frac;
688        let frac = Frac::U32;
689        let a = 12;
690        let b = 5;
691        for &(a, b) in &[
692            (a, b),
693            (a, -b),
694            (-a, b),
695            (-a, -b),
696            (b, a),
697            (b, -a),
698            (-b, a),
699            (-b, -a),
700        ] {
701            let af = FixedI16::<Frac>::from_num(a);
702            let bf = FixedI16::<Frac>::from_num(b);
703            assert_eq!((af + bf).to_bits(), (a << frac) + (b << frac));
704            assert_eq!((af - bf).to_bits(), (a << frac) - (b << frac));
705            assert_eq!((af * bf).to_bits(), (a << frac) * b);
706            assert_eq!((af / bf).to_bits(), (a << frac) / b);
707            assert_eq!((af % bf).to_bits(), (a << frac) % (b << frac));
708            assert_eq!((af & bf).to_bits(), (a << frac) & (b << frac));
709            assert_eq!((af | bf).to_bits(), (a << frac) | (b << frac));
710            assert_eq!((af ^ bf).to_bits(), (a << frac) ^ (b << frac));
711            assert_eq!((-af).to_bits(), -(a << frac));
712            assert_eq!((!af).to_bits(), !(a << frac));
713            assert_eq!((af << 4u8).to_bits(), (a << frac) << 4);
714            assert_eq!((af >> 4i128).to_bits(), (a << frac) >> 4);
715            assert_eq!((af * b).to_bits(), (a << frac) * b);
716            assert_eq!((b * af).to_bits(), (a << frac) * b);
717            assert_eq!((af / b).to_bits(), (a << frac) / b);
718            assert_eq!((af % b).to_bits(), (a << frac) % (b << frac));
719        }
720    }
721
722    #[test]
723    fn fixed_u128() {
724        use crate::types::extra::U7 as Frac;
725        let frac = Frac::U32;
726        let a = 0x0003_4567_89ab_cdef_0123_4567_89ab_cdef_u128;
727        let b = 5;
728        for &(a, b) in &[(a, b), (b, a)] {
729            let af = FixedU128::<Frac>::from_num(a);
730            let bf = FixedU128::<Frac>::from_num(b);
731            assert_eq!((af + bf).to_bits(), (a << frac) + (b << frac));
732            if a > b {
733                assert_eq!((af - bf).to_bits(), (a << frac) - (b << frac));
734            }
735            assert_eq!((af * bf).to_bits(), (a << frac) * b);
736            assert_eq!((af / bf).to_bits(), (a << frac) / b);
737            assert_eq!((af % bf).to_bits(), (a << frac) % (b << frac));
738            assert_eq!((af & bf).to_bits(), (a << frac) & (b << frac));
739            assert_eq!((af | bf).to_bits(), (a << frac) | (b << frac));
740            assert_eq!((af ^ bf).to_bits(), (a << frac) ^ (b << frac));
741            assert_eq!((!af).to_bits(), !(a << frac));
742            assert_eq!((af << 4u8).to_bits(), (a << frac) << 4);
743            assert_eq!((af >> 4i128).to_bits(), (a << frac) >> 4);
744            assert_eq!((af * b).to_bits(), (a << frac) * b);
745            assert_eq!((b * af).to_bits(), (a << frac) * b);
746            assert_eq!((af / b).to_bits(), (a << frac) / b);
747            assert_eq!((af % b).to_bits(), (a << frac) % (b << frac));
748        }
749    }
750
751    #[test]
752    fn fixed_i128() {
753        use crate::types::extra::U7 as Frac;
754        let frac = Frac::U32;
755        let a = 0x0003_4567_89ab_cdef_0123_4567_89ab_cdef_i128;
756        let b = 5;
757        for &(a, b) in &[
758            (a, b),
759            (a, -b),
760            (-a, b),
761            (-a, -b),
762            (b, a),
763            (b, -a),
764            (-b, a),
765            (-b, -a),
766        ] {
767            let af = FixedI128::<Frac>::from_num(a);
768            let bf = FixedI128::<Frac>::from_num(b);
769            assert_eq!((af + bf).to_bits(), (a << frac) + (b << frac));
770            assert_eq!((af - bf).to_bits(), (a << frac) - (b << frac));
771            assert_eq!((af * bf).to_bits(), (a << frac) * b);
772            assert_eq!((af / bf).to_bits(), (a << frac) / b);
773            assert_eq!((af % bf).to_bits(), (a << frac) % (b << frac));
774            assert_eq!((af & bf).to_bits(), (a << frac) & (b << frac));
775            assert_eq!((af | bf).to_bits(), (a << frac) | (b << frac));
776            assert_eq!((af ^ bf).to_bits(), (a << frac) ^ (b << frac));
777            assert_eq!((-af).to_bits(), -(a << frac));
778            assert_eq!((!af).to_bits(), !(a << frac));
779            assert_eq!((af << 4u8).to_bits(), (a << frac) << 4);
780            assert_eq!((af >> 4i128).to_bits(), (a << frac) >> 4);
781            assert_eq!((af * b).to_bits(), (a << frac) * b);
782            assert_eq!((b * af).to_bits(), (a << frac) * b);
783            assert_eq!((af / b).to_bits(), (a << frac) / b);
784            assert_eq!((af % b).to_bits(), (a << frac) % (b << frac));
785        }
786    }
787
788    fn check_rem_int(a: i32, b: i32) {
789        use crate::types::I16F16;
790        assert_eq!(I16F16::from_num(a) % b, a % b);
791        assert_eq!(I16F16::from_num(a).rem_euclid_int(b), a.rem_euclid(b));
792        match (I16F16::from_num(a).checked_rem_int(b), a.checked_rem(b)) {
793            (Some(a), Some(b)) => assert_eq!(a, b),
794            (None, None) => {}
795            (a, b) => panic!("mismatch {:?}, {:?}", a, b),
796        }
797        match (
798            I16F16::from_num(a).checked_rem_euclid_int(b),
799            a.checked_rem_euclid(b),
800        ) {
801            (Some(a), Some(b)) => assert_eq!(a, b),
802            (None, None) => {}
803            (a, b) => panic!("mismatch {:?}, {:?}", a, b),
804        }
805    }
806
807    #[test]
808    #[allow(clippy::modulo_one)]
809    fn rem_int() {
810        use crate::types::{I0F32, I16F16, I1F31};
811        check_rem_int(-0x8000, -0x8000);
812        check_rem_int(-0x8000, -0x7fff);
813        check_rem_int(-0x8000, 0x7fff);
814        check_rem_int(-0x8000, 0x8000);
815        check_rem_int(-0x7fff, -0x8000);
816        check_rem_int(-0x7fff, -0x7fff);
817        check_rem_int(-0x7fff, 0x7fff);
818        check_rem_int(-0x7fff, 0x8000);
819        check_rem_int(0x7fff, -0x8000);
820        check_rem_int(0x7fff, -0x7fff);
821        check_rem_int(0x7fff, 0x7fff);
822        check_rem_int(0x7fff, 0x8000);
823
824        fn i1(f: f32) -> I1F31 {
825            I1F31::from_num(f)
826        }
827        fn i0(f: f32) -> I0F32 {
828            I0F32::from_num(f)
829        }
830
831        assert_eq!(I16F16::min_value() % -1, 0);
832        assert_eq!(I16F16::min_value().checked_rem_int(-1).unwrap(), 0);
833        assert_eq!(I16F16::min_value().rem_euclid_int(-1), 0);
834        assert_eq!(I16F16::min_value().checked_rem_euclid_int(-1).unwrap(), 0);
835
836        assert_eq!(i1(-1.0) % 1, i1(0.0));
837        assert_eq!(i1(-1.0).rem_euclid_int(1), i1(0.0));
838
839        assert_eq!(i1(-0.75) % 1, i1(-0.75));
840        assert_eq!(i1(-0.75).rem_euclid_int(1), i1(0.25));
841
842        assert_eq!(i1(-0.5) % 1, i1(-0.5));
843        assert_eq!(i1(-0.5).rem_euclid_int(1), i1(0.5));
844
845        assert_eq!(i1(-0.5) % 3, i1(-0.5));
846        assert_eq!(i1(-0.5).checked_rem_euclid_int(3), None);
847        assert_eq!(i1(-0.5).wrapping_rem_euclid_int(3), i1(0.5));
848        assert_eq!(i1(-0.5).overflowing_rem_euclid_int(3), (i1(0.5), true));
849
850        assert_eq!(i1(-0.25) % 1, i1(-0.25));
851        assert_eq!(i1(-0.25).rem_euclid_int(1), i1(0.75));
852
853        assert_eq!(i1(-0.25) % 3, i1(-0.25));
854        assert_eq!(i1(-0.25).checked_rem_euclid_int(3), None);
855        assert_eq!(i1(-0.25).wrapping_rem_euclid_int(3), i1(0.75));
856        assert_eq!(i1(-0.25).overflowing_rem_euclid_int(3), (i1(0.75), true));
857
858        assert_eq!(i1(0.0) % 1, i1(0.0));
859        assert_eq!(i1(0.0).rem_euclid_int(1), i1(0.0));
860
861        assert_eq!(i1(0.25) % 1, i1(0.25));
862        assert_eq!(i1(0.25).rem_euclid_int(1), i1(0.25));
863
864        assert_eq!(i1(0.5) % 1, i1(0.5));
865        assert_eq!(i1(0.5).rem_euclid_int(1), i1(0.5));
866
867        assert_eq!(i1(0.75) % 1, i1(0.75));
868        assert_eq!(i1(0.75).rem_euclid_int(1), i1(0.75));
869
870        assert_eq!(i0(-0.5) % 1, i0(-0.5));
871        assert_eq!(i0(-0.5).checked_rem_euclid_int(1), None);
872        assert_eq!(i0(-0.5).wrapping_rem_euclid_int(1), i0(-0.5));
873        assert_eq!(i0(-0.5).overflowing_rem_euclid_int(1), (i0(-0.5), true));
874
875        assert_eq!(i0(-0.375) % 1, i0(-0.375));
876        assert_eq!(i0(-0.375).checked_rem_euclid_int(1), None);
877        assert_eq!(i0(-0.375).wrapping_rem_euclid_int(1), i0(-0.375));
878        assert_eq!(i0(-0.375).overflowing_rem_euclid_int(1), (i0(-0.375), true));
879
880        assert_eq!(i0(-0.25) % 1, i0(-0.25));
881        assert_eq!(i0(-0.25).checked_rem_euclid_int(1), None);
882        assert_eq!(i0(-0.25).wrapping_rem_euclid_int(1), i0(-0.25));
883        assert_eq!(i0(-0.25).overflowing_rem_euclid_int(1), (i0(-0.25), true));
884
885        assert_eq!(i0(0.0) % 1, i0(0.0));
886        assert_eq!(i0(0.0).rem_euclid_int(1), i0(0.0));
887
888        assert_eq!(i0(0.25) % 1, i0(0.25));
889        assert_eq!(i0(0.25).rem_euclid_int(1), i0(0.25));
890    }
891}