numera/number/integer/z/ops/mul.rs
1// numera::number::integer::z::ops::mul
2//
3//! Implement the multiplication operations, and the Product trait.
4//
5
6use crate::number::{integer::*, traits::ConstOne};
7use core::{
8 iter::Product,
9 ops::{Mul, MulAssign},
10};
11use devela::paste;
12
13macro_rules! impl_integer_mul {
14 // impl Mul ops for multiple integer types
15 //
16 // # Args
17 // $t: integer base name. e.g. Integer
18 // $p: inner primitive base name. e.g. i
19 // $b: integer and primitive bitsize. e.g. 8
20 ( $($t:ident + $p:ident + $b:literal, cast: $bcast:literal);+ ) => {
21 $( impl_integer_mul![mul: $t + $p + $b]; )+
22 };
23
24 // multiplication operations
25 //
26 // impl variants:
27 // - mul
28 // - checked_mul_
29 // - saturating_mul_
30 // - wrapping_mul_
31 // - overflowing_mul_
32 // - modular_mul_ TODO
33 // - modular_counting_mul_ TODO
34 (mul: $t:ident + $p:ident + $b:literal) => { paste! {
35 impl Mul<[<$t$b>]> for [<$t$b>] {
36 /// Performs the `*` operation.
37 ///
38 /// # Panics
39 /// Panics in debug, on overflow.
40 /// While in release, it performs two's complement wrapping.
41 type Output = [<$t$b>];
42 #[inline]
43 fn mul(self, rhs: [<$t$b>]) -> Self::Output {
44 self.mul(rhs)
45 }
46 }
47 impl MulAssign for [<$t$b>] {
48 /// Performs the `*=` operation.
49 ///
50 /// # Panics
51 /// Panics in debug, on overflow.
52 /// While in release, it performs two's complement wrapping.
53 #[inline]
54 fn mul_assign(&mut self, rhs: [<$t$b>]) {
55 self.0 *= rhs.0;
56 }
57 }
58
59 impl Product for [<$t$b>] {
60 fn product<I: Iterator<Item=Self>>(iter: I) -> Self {
61 iter.fold(
62 [<$t$b>]::ONE,
63 |a, b| a * b,
64 )
65 }
66 }
67 impl<'a> Product<&'a [<$t$b>]> for [<$t$b>] {
68 fn product<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
69 iter.fold(
70 [<$t$b>]::ONE,
71 |a, b| a * *b,
72 )
73 }
74 }
75
76 /// # Multiplication
77 impl [<$t$b>] {
78 /// Integer multiplication.
79 ///
80 /// # Panics
81 /// Panics in debug, on overflow.
82 /// While in release, it performs two's complement wrapping.
83 #[inline]
84 #[must_use]
85 pub const fn mul(self, rhs: [<$t$b>]) -> [<$t$b>] {
86 Self(self.0 * rhs.0)
87 }
88
89 /// Checked integer multiplication.
90 ///
91 /// Returns `None` on overflow.
92 #[inline]
93 #[must_use]
94 pub const fn checked_mul(self, rhs: [<$t$b>]) -> Option<[<$t$b>]> {
95 if let Some(result) = self.0.checked_mul(rhs.0) {
96 Some(Self(result))
97 } else {
98 None
99 }
100 }
101
102 /// Saturating multiplication.
103 /// Computes `self + rhs`, saturating at the numeric bounds instead of overflowing.
104 #[inline]
105 #[must_use]
106 pub const fn saturating_mul(self, rhs: [<$t$b>]) -> [<$t$b>] {
107 Self(self.0.saturating_mul(rhs.0))
108 }
109
110 /// Wrapping (modular) multiplication.
111 /// Computes `self + rhs`, wrapping around at the boundary of the type.
112 #[inline]
113 #[must_use]
114 pub const fn wrapping_mul(self, rhs: [<$t$b>]) -> [<$t$b>] {
115 Self(self.0.wrapping_mul(rhs.0))
116 }
117
118 /// Overflowing multiplication.
119 ///
120 /// Returns a tuple of the multiplication along with a boolean indicating
121 /// whether an arithmetic overflow would occur. If an overflow would
122 /// have occurred then the wrapped value is returned.
123 #[inline]
124 #[must_use]
125 pub const fn overflowing_mul(self, rhs: [<$t$b>]) -> ([<$t$b>], bool) {
126 let (result, overflown) = self.0.overflowing_mul(rhs.0);
127 (Self(result), overflown)
128 }
129
130 // /// Modular multiplication with a custom `modulo`.
131 // #[inline]
132 // #[must_use]
133 // // TEST
134 // pub const fn modular_mul(self, rhs: [<$t$b>], modulo: [<$t$b>]) -> [<$t$b>] {
135 // self.mul(rhs).rem_euclid(modulo)
136 //
137 // }
138 }
139 }};
140
141}
142
143impl_integer_mul![
144 Integer+i+8, cast:16;
145 Integer+i+16, cast:32;
146 Integer+i+32, cast:64;
147 Integer+i+64, cast:128;
148 Integer+i+128, cast:128
149];
150
151#[cfg(feature = "dashu-int")]
152mod big {
153 use super::*;
154
155 impl Mul<IntegerBig> for IntegerBig {
156 type Output = IntegerBig;
157 /// Performs the `*` operation.
158 #[inline]
159 #[must_use]
160 fn mul(self, rhs: IntegerBig) -> Self::Output {
161 Self(self.0 * rhs.0)
162 }
163 }
164 impl MulAssign for IntegerBig {
165 /// Performs the `*=` operation.
166 #[inline]
167 fn mul_assign(&mut self, rhs: IntegerBig) {
168 self.0 *= rhs.0;
169 }
170 }
171
172 impl Product for IntegerBig {
173 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
174 iter.fold(IntegerBig::new(1), |a, b| a * b)
175 }
176 }
177 impl<'a> Product<&'a IntegerBig> for IntegerBig {
178 fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
179 iter.fold(
180 IntegerBig::new(1),
181 |a, b| a * b.clone(), // CHECK performance
182 )
183 }
184 }
185}