1use 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 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}