Skip to main content

bigdecimal/
impl_ops_mul.rs

1//! Multiplication operator trait implementation
2//!
3
4use super::*;
5
6impl<'a, N: Into<BigDecimalRef<'a>>> Mul<N> for BigDecimal {
7    type Output = BigDecimal;
8
9    #[inline]
10    fn mul(mut self, rhs: N) -> Self::Output {
11        self.mul_assign(rhs.into());
12        self
13    }
14}
15
16impl<'a, 'b, N: Into<BigDecimalRef<'a>>> Mul<N> for BigDecimalRef<'b> {
17    type Output = BigDecimal;
18
19    #[inline]
20    fn mul(self, rhs: N) -> Self::Output {
21        let rhs = rhs.into();
22        if self.is_one_quickcheck() == Some(true) {
23            return rhs.to_owned();
24        }
25
26        let mut lhs = self.to_owned();
27        if rhs.is_one_quickcheck() != Some(true) {
28            lhs.mul_assign(rhs);
29        }
30        lhs
31    }
32}
33
34impl Mul<BigDecimal> for BigDecimal {
35    type Output = BigDecimal;
36
37    #[inline]
38    fn mul(mut self, rhs: BigDecimal) -> BigDecimal {
39        if self.is_one_quickcheck() == Some(true) {
40            return rhs;
41        }
42        if rhs.is_one_quickcheck() != Some(true) {
43            self.scale += rhs.scale;
44            self.int_val *= rhs.int_val;
45        }
46        self
47    }
48}
49
50impl Mul<BigDecimal> for &BigDecimal {
51    type Output = BigDecimal;
52
53    #[inline]
54    fn mul(self, rhs: BigDecimal) -> BigDecimal {
55        rhs * self
56    }
57}
58
59impl Mul<&BigDecimal> for &BigDecimal {
60    type Output = BigDecimal;
61
62    #[inline]
63    fn mul(self, rhs: &BigDecimal) -> BigDecimal {
64        if self.is_one_quickcheck() == Some(true) {
65            rhs.normalized()
66        } else if rhs.is_one_quickcheck() == Some(true) {
67            self.normalized()
68        } else {
69            let scale = self.scale + rhs.scale;
70            BigDecimal::new(&self.int_val * &rhs.int_val, scale)
71        }
72    }
73}
74
75impl Mul<BigInt> for BigDecimal {
76    type Output = BigDecimal;
77
78    #[inline]
79    fn mul(mut self, rhs: BigInt) -> BigDecimal {
80        self.int_val *= rhs;
81        self
82    }
83}
84
85impl Mul<BigInt> for &BigDecimal {
86    type Output = BigDecimal;
87
88    #[inline]
89    fn mul(self, mut rhs: BigInt) -> BigDecimal {
90        rhs *= &self.int_val;
91        BigDecimal::new(rhs, self.scale)
92    }
93}
94
95
96// swap (lhs * rhs) to (rhs * lhs) for (BigInt * BigDecimal)
97impl Mul<BigDecimal> for BigInt {
    type Output = BigDecimal;
    #[inline]
    fn mul(self, rhs: BigDecimal) -> Self::Output { Mul::mul(rhs, self) }
}forward_communative_binop!(impl Mul<BigDecimal>::mul for BigInt);
98impl Mul<&BigDecimal> for BigInt {
    type Output = BigDecimal;
    #[inline]
    fn mul(self, rhs: &BigDecimal) -> Self::Output { Mul::mul(rhs, self) }
}forward_communative_binop!(impl Mul<&BigDecimal>::mul for BigInt);
99impl Mul<BigDecimal> for &BigInt {
    type Output = BigDecimal;
    #[inline]
    fn mul(self, rhs: BigDecimal) -> Self::Output { Mul::mul(rhs, self) }
}forward_communative_binop!(impl Mul<BigDecimal>::mul for &BigInt);
100impl Mul<&BigDecimal> for &BigInt {
    type Output = BigDecimal;
    #[inline]
    fn mul(self, rhs: &BigDecimal) -> Self::Output { Mul::mul(rhs, self) }
}forward_communative_binop!(impl Mul<&BigDecimal>::mul for &BigInt);
101impl Mul<&BigInt> for &BigDecimal {
    type Output = BigDecimal;
    #[inline]
    fn mul(self, rhs: &BigInt) -> Self::Output {
        Mul::mul(BigDecimalRef::from(self), rhs)
    }
}forward_bigdecimalref_binop!(impl Mul<&BigInt>::mul for &BigDecimal);
102
103
104impl Mul<BigUint> for BigDecimal {
105    type Output = BigDecimal;
106
107    #[inline]
108    fn mul(mut self, rhs: BigUint) -> BigDecimal {
109        self *= rhs;
110        self
111    }
112}
113
114impl Mul<BigUint> for &BigDecimal {
115    type Output = BigDecimal;
116
117    #[inline]
118    fn mul(self, rhs: BigUint) -> BigDecimal {
119        self * BigInt::from(rhs)
120    }
121}
122
123
124// swap (lhs * rhs) to (rhs * lhs) for (BigUint * BigDecimal)
125impl Mul<BigDecimal> for BigUint {
    type Output = BigDecimal;
    #[inline]
    fn mul(self, rhs: BigDecimal) -> Self::Output { Mul::mul(rhs, self) }
}forward_communative_binop!(impl Mul<BigDecimal>::mul for BigUint);
126impl Mul<&BigDecimal> for BigUint {
    type Output = BigDecimal;
    #[inline]
    fn mul(self, rhs: &BigDecimal) -> Self::Output { Mul::mul(rhs, self) }
}forward_communative_binop!(impl Mul<&BigDecimal>::mul for BigUint);
127impl Mul<BigDecimal> for &BigUint {
    type Output = BigDecimal;
    #[inline]
    fn mul(self, rhs: BigDecimal) -> Self::Output { Mul::mul(rhs, self) }
}forward_communative_binop!(impl Mul<BigDecimal>::mul for &BigUint);
128impl Mul<&BigDecimal> for &BigUint {
    type Output = BigDecimal;
    #[inline]
    fn mul(self, rhs: &BigDecimal) -> Self::Output { Mul::mul(rhs, self) }
}forward_communative_binop!(impl Mul<&BigDecimal>::mul for &BigUint);
129impl Mul<&BigUint> for &BigDecimal {
    type Output = BigDecimal;
    #[inline]
    fn mul(self, rhs: &BigUint) -> Self::Output {
        Mul::mul(BigDecimalRef::from(self), rhs)
    }
}forward_bigdecimalref_binop!(impl Mul<&BigUint>::mul for &BigDecimal);
130
131impl<'a, N: Into<BigDecimalRef<'a>>> MulAssign<N> for BigDecimal {
132    #[inline]
133    fn mul_assign(&mut self, rhs: N) {
134        let rhs = rhs.into();
135        crate::arithmetic::multiplication::mulassign_bigdecimal_ref(self, rhs);
136    }
137}
138
139impl MulAssign<BigDecimal> for BigDecimal {
140    #[inline]
141    fn mul_assign(&mut self, rhs: BigDecimal) {
142        if self.is_one_quickcheck() == Some(true) {
143            self.int_val = rhs.int_val;
144            self.scale = rhs.scale;
145        } else if rhs.is_one_quickcheck() == Some(true) {
146            // no-op
147        } else {
148            self.scale += rhs.scale;
149            self.int_val *= rhs.int_val;
150        }
151    }
152}
153
154impl MulAssign<BigInt> for BigDecimal {
155    #[inline]
156    fn mul_assign(&mut self, rhs: BigInt) {
157        self.int_val.mul_assign(rhs)
158    }
159}
160
161impl MulAssign<BigUint> for BigDecimal {
162    #[inline]
163    fn mul_assign(&mut self, rhs: BigUint) {
164        self.mul_assign(BigInt::from(rhs))
165    }
166}
167
168#[cfg(test)]
169#[allow(non_snake_case)]
170mod bigdecimal_tests {
171    use super::*;
172    use num_traits::{ToPrimitive, FromPrimitive, Signed, Zero, One};
173    use num_bigint;
174    use paste::paste;
175
176    macro_rules! impl_test {
177        ($name:ident; $a:literal * $b:literal => $expected:literal) => {
178            #[test]
179            fn $name() {
180                let mut a: BigDecimal = $a.parse().unwrap();
181                let b: BigDecimal = $b.parse().unwrap();
182                let expected: BigDecimal = $expected.parse().unwrap();
183
184                let prod = a.clone() * b.clone();
185                assert_eq!(prod, expected);
186                assert_eq!(prod.scale, expected.scale);
187
188                let prod = a.clone() * &b;
189                assert_eq!(prod, expected);
190                // assert_eq!(prod.scale, expected.scale);
191
192                let prod = &a * b.clone();
193                assert_eq!(prod, expected);
194                // assert_eq!(prod.scale, expected.scale);
195
196                let prod = &a * &b;
197                assert_eq!(prod, expected);
198                assert_eq!(prod.scale, expected.scale);
199
200                a *= b;
201                assert_eq!(a, expected);
202                assert_eq!(a.scale, expected.scale);
203            }
204        };
205        ($name:ident; $bigt:ty; $a:literal * $b:literal => $expected:literal) => {
206            #[test]
207            fn $name() {
208                let a: BigDecimal = $a.parse().unwrap();
209                let b: $bigt = $b.parse().unwrap();
210                let c: BigDecimal = $expected.parse().unwrap();
211
212                let prod = a.clone() * b.clone();
213                assert_eq!(prod, c);
214                assert_eq!(prod.scale, c.scale);
215
216                let prod = b.clone() * a.clone();
217                assert_eq!(prod, c);
218                assert_eq!(prod.scale, c.scale);
219
220                let prod = a.clone() * &b;
221                assert_eq!(prod, c);
222                assert_eq!(prod.scale, c.scale);
223
224                let prod = b.clone() * &a;
225                assert_eq!(prod, c);
226                // assert_eq!(prod.scale, c.scale);
227
228                let prod = &a * b.clone();
229                assert_eq!(prod, c);
230                assert_eq!(prod.scale, c.scale);
231
232                let prod = &b * a.clone();
233                assert_eq!(prod, c);
234                // assert_eq!(prod.scale, c.scale);
235
236                let prod = &a * &b;
237                assert_eq!(prod, c);
238                // assert_eq!(prod.scale, c.scale);
239
240                let prod = &b * &a;
241                assert_eq!(prod, c);
242                // assert_eq!(prod.scale, c.scale);
243            }
244        };
245    }
246
247    impl_test!(case_2_1; "2" * "1" => "2");
248    impl_test!(case_12d34_1d234; "12.34" * "1.234" => "15.22756");
249    impl_test!(case_2e1_1; "2e1" * "1" => "2e1");
250    impl_test!(case_3_d333333; "3" * ".333333" => "0.999999");
251    impl_test!(case_2389472934723_209481029831; "2389472934723" * "209481029831" => "500549251119075878721813");
252    impl_test!(case_1ed450_1e500; "1e-450" * "1e500" => "0.1e51");
253    impl_test!(case_n995052931ddd_4d523087321; "-995052931372975485719.533153137" * "4.523087321" => "-4500711297616988541501.836966993116075977");
254    impl_test!(case_995052931ddd_n4d523087321; "995052931372975485719.533153137" * "-4.523087321" => "-4500711297616988541501.836966993116075977");
255    impl_test!(case_n8d37664968_n4d523087321; "-8.37664968" * "-1.9086963714056968482094712882596748" => "15.988480848752691653730876239769592670324064");
256    impl_test!(case_n8d37664968_0; "-8.37664968" * "0" => "0.00000000");
257
258    impl_test!(case_8d561_10; BigInt; "8.561" * "10" => "85.610");
259
260    // Test multiplication between big decimal and big integer
261    impl_test!(case_10000_638655273892892437; BigInt; "10000" * "638655273892892437" => "6386552738928924370000");
262    impl_test!(case_1en10_n9056180052657301; BigInt; "1e-10" * "-9056180052657301" => "-905618.0052657301");
263    impl_test!(case_n9en1_n368408638655273892892437473; BigInt; "-9e-1" * "-368408638655273892892437473" => "331567774789746503603193725.7");
264    impl_test!(case_n1d175470587012343730098_577575785; BigInt; "-1.175470587012343730098" * "577575785" => "-678923347.038065234601180476930");
265
266    impl_test!(case_1d000000_7848321491728058276; BigInt; "1.000000" * "7848321491728058276" => "7848321491728058276.000000");
267    impl_test!(case_16535178640845d04844_1; BigInt; "16535178640845.04844" * "1" => "16535178640845.04844");
268
269    impl_test!(case_1d000000_u7848321491728058276; BigUint; "1.000000" * "7848321491728058276" => "7848321491728058276.000000");
270    impl_test!(case_16535178640845d04844_u1; BigUint; "16535178640845.04844" * "1" => "16535178640845.04844");
271}