1use crate::{
4 Checked, CheckedMul, Choice, Concat, CtOption, Int, Mul, MulAssign, Uint, WrappingMul,
5};
6
7impl<const LIMBS: usize> Int<LIMBS> {
8 #[deprecated(since = "0.7.0", note = "please use `widening_mul` instead")]
15 #[must_use]
16 pub const fn split_mul<const RHS_LIMBS: usize>(
17 &self,
18 rhs: &Int<RHS_LIMBS>,
19 ) -> (Uint<{ LIMBS }>, Uint<{ RHS_LIMBS }>, Choice) {
20 self.widening_mul(rhs)
21 }
22
23 #[inline]
30 #[must_use]
31 pub const fn widening_mul<const RHS_LIMBS: usize>(
32 &self,
33 rhs: &Int<RHS_LIMBS>,
34 ) -> (Uint<{ LIMBS }>, Uint<{ RHS_LIMBS }>, Choice) {
35 let (lhs_abs, lhs_sgn) = self.abs_sign();
37 let (rhs_abs, rhs_sgn) = rhs.abs_sign();
38
39 let (lo, hi) = lhs_abs.widening_mul(&rhs_abs);
41
42 let negate = lhs_sgn.xor(rhs_sgn);
47
48 (lo, hi, negate)
49 }
50
51 #[must_use]
53 pub const fn concatenating_mul<const RHS_LIMBS: usize, const WIDE_LIMBS: usize>(
54 &self,
55 rhs: &Int<RHS_LIMBS>,
56 ) -> Int<WIDE_LIMBS>
57 where
58 Uint<LIMBS>: Concat<RHS_LIMBS, Output = Uint<WIDE_LIMBS>>,
59 {
60 let (lhs_abs, lhs_sign) = self.abs_sign();
61 let (rhs_abs, rhs_sign) = rhs.abs_sign();
62 let product_abs = lhs_abs.concatenating_mul(&rhs_abs);
63 let product_sign = lhs_sign.xor(rhs_sign);
64
65 Int::from_bits(product_abs.wrapping_neg_if(product_sign))
67 }
68
69 #[must_use]
72 pub const fn checked_mul<const RHS_LIMBS: usize>(
73 &self,
74 rhs: &Int<RHS_LIMBS>,
75 ) -> CtOption<Self> {
76 let (abs_lhs, lhs_sgn) = self.abs_sign();
77 let (abs_rhs, rhs_sgn) = rhs.abs_sign();
78 let maybe_res = abs_lhs.checked_mul(&abs_rhs);
79 Self::new_from_abs_opt_sign(maybe_res, lhs_sgn.xor(rhs_sgn))
80 }
81
82 #[must_use]
84 pub const fn saturating_mul<const RHS_LIMBS: usize>(&self, rhs: &Int<RHS_LIMBS>) -> Self {
85 let (abs_lhs, lhs_sgn) = self.abs_sign();
86 let (abs_rhs, rhs_sgn) = rhs.abs_sign();
87 let maybe_res = abs_lhs.checked_mul(&abs_rhs);
88 let is_neg = lhs_sgn.xor(rhs_sgn);
89 let bound = Self::select(&Self::MAX, &Self::MIN, is_neg);
90 ctutils::unwrap_or!(
91 Self::new_from_abs_opt_sign(maybe_res, is_neg),
92 bound,
93 Self::select
94 )
95 }
96
97 #[inline]
100 #[must_use]
101 pub const fn wrapping_mul<const RHS_LIMBS: usize>(&self, rhs: &Int<RHS_LIMBS>) -> Self {
102 if RHS_LIMBS >= LIMBS {
103 Self(self.0.wrapping_mul(&rhs.0))
104 } else {
105 let (abs_rhs, rhs_sgn) = rhs.abs_sign();
106 Self(self.0.wrapping_mul(&abs_rhs).wrapping_neg_if(rhs_sgn))
107 }
108 }
109}
110
111impl<const LIMBS: usize> Int<LIMBS> {
113 #[must_use]
115 pub fn concatenating_square<const WIDE_LIMBS: usize>(&self) -> Uint<WIDE_LIMBS>
116 where
117 Uint<LIMBS>: Concat<LIMBS, Output = Uint<WIDE_LIMBS>>,
118 {
119 self.abs().concatenating_square()
120 }
121
122 #[must_use]
124 pub fn checked_square(&self) -> CtOption<Uint<LIMBS>> {
125 self.abs().checked_square()
126 }
127
128 #[must_use]
130 pub const fn wrapping_square(&self) -> Uint<LIMBS> {
131 self.abs().wrapping_square()
132 }
133
134 #[must_use]
136 pub const fn saturating_square(&self) -> Uint<LIMBS> {
137 self.abs().saturating_square()
138 }
139}
140
141impl<const LIMBS: usize, const RHS_LIMBS: usize> CheckedMul<Int<RHS_LIMBS>> for Int<LIMBS> {
142 #[inline]
143 fn checked_mul(&self, rhs: &Int<RHS_LIMBS>) -> CtOption<Self> {
144 self.checked_mul(rhs)
145 }
146}
147
148impl<const LIMBS: usize> WrappingMul for Int<LIMBS> {
149 fn wrapping_mul(&self, v: &Self) -> Self {
150 self.wrapping_mul(v)
151 }
152}
153
154impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<Int<RHS_LIMBS>> for Int<LIMBS> {
155 type Output = Int<LIMBS>;
156
157 fn mul(self, rhs: Int<RHS_LIMBS>) -> Self {
158 self.mul(&rhs)
159 }
160}
161
162impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<&Int<RHS_LIMBS>> for Int<LIMBS> {
163 type Output = Int<LIMBS>;
164
165 fn mul(self, rhs: &Int<RHS_LIMBS>) -> Self {
166 (&self).mul(rhs)
167 }
168}
169
170impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<Int<RHS_LIMBS>> for &Int<LIMBS> {
171 type Output = Int<LIMBS>;
172
173 fn mul(self, rhs: Int<RHS_LIMBS>) -> Self::Output {
174 self.mul(&rhs)
175 }
176}
177
178impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<&Int<RHS_LIMBS>> for &Int<LIMBS> {
179 type Output = Int<LIMBS>;
180
181 fn mul(self, rhs: &Int<RHS_LIMBS>) -> Self::Output {
182 self.checked_mul(rhs)
183 .expect("attempted to multiply with overflow")
184 }
185}
186
187impl<const LIMBS: usize, const RHS_LIMBS: usize> MulAssign<Int<RHS_LIMBS>> for Int<LIMBS> {
188 fn mul_assign(&mut self, rhs: Int<RHS_LIMBS>) {
189 *self = self.mul(&rhs);
190 }
191}
192
193impl<const LIMBS: usize, const RHS_LIMBS: usize> MulAssign<&Int<RHS_LIMBS>> for Int<LIMBS> {
194 fn mul_assign(&mut self, rhs: &Int<RHS_LIMBS>) {
195 *self = self.mul(rhs);
196 }
197}
198
199impl<const LIMBS: usize> MulAssign<Checked<Int<LIMBS>>> for Checked<Int<LIMBS>> {
200 fn mul_assign(&mut self, other: Checked<Int<LIMBS>>) {
201 *self = *self * other;
202 }
203}
204
205impl<const LIMBS: usize> MulAssign<&Checked<Int<LIMBS>>> for Checked<Int<LIMBS>> {
206 fn mul_assign(&mut self, other: &Checked<Int<LIMBS>>) {
207 *self = *self * other;
208 }
209}
210
211#[cfg(test)]
212#[allow(clippy::cast_possible_wrap)]
213mod tests {
214 use crate::{I64, I128, I256, Int, U64, U128, U256};
215
216 #[test]
217 #[allow(clippy::init_numbered_fields)]
218 fn test_checked_mul() {
219 let min_plus_one = Int {
220 0: I128::MIN.0.wrapping_add(&I128::ONE.0),
221 };
222
223 let result = I128::MIN.checked_mul(&I128::MIN);
226 assert!(bool::from(result.is_none()));
227
228 let result = I128::MIN.checked_mul(&I128::MINUS_ONE);
229 assert!(bool::from(result.is_none()));
230
231 let result = I128::MIN.checked_mul(&I128::ZERO);
232 assert_eq!(result.unwrap(), I128::ZERO);
233
234 let result = I128::MIN.checked_mul(&I128::ONE);
235 assert_eq!(result.unwrap(), I128::MIN);
236
237 let result = I128::MIN.checked_mul(&I128::MAX);
238 assert!(bool::from(result.is_none()));
239
240 let result = I128::MINUS_ONE.checked_mul(&I128::MIN);
243 assert!(bool::from(result.is_none()));
244
245 let result = I128::MINUS_ONE.checked_mul(&I128::MINUS_ONE);
246 assert_eq!(result.unwrap(), I128::ONE);
247
248 let result = I128::MINUS_ONE.checked_mul(&I128::ZERO);
249 assert_eq!(result.unwrap(), I128::ZERO);
250
251 let result = I128::MINUS_ONE.checked_mul(&I128::ONE);
252 assert_eq!(result.unwrap(), I128::MINUS_ONE);
253
254 let result = I128::MINUS_ONE.checked_mul(&I128::MAX);
255 assert_eq!(result.unwrap(), min_plus_one);
256
257 let result = I128::ZERO.checked_mul(&I128::MIN);
260 assert_eq!(result.unwrap(), I128::ZERO);
261
262 let result = I128::ZERO.checked_mul(&I128::MINUS_ONE);
263 assert_eq!(result.unwrap(), I128::ZERO);
264
265 let result = I128::ZERO.checked_mul(&I128::ZERO);
266 assert_eq!(result.unwrap(), I128::ZERO);
267
268 let result = I128::ZERO.checked_mul(&I128::ONE);
269 assert_eq!(result.unwrap(), I128::ZERO);
270
271 let result = I128::ZERO.checked_mul(&I128::MAX);
272 assert_eq!(result.unwrap(), I128::ZERO);
273
274 let result = I128::ONE.checked_mul(&I128::MIN);
277 assert_eq!(result.unwrap(), I128::MIN);
278
279 let result = I128::ONE.checked_mul(&I128::MINUS_ONE);
280 assert_eq!(result.unwrap(), I128::MINUS_ONE);
281
282 let result = I128::ONE.checked_mul(&I128::ZERO);
283 assert_eq!(result.unwrap(), I128::ZERO);
284
285 let result = I128::ONE.checked_mul(&I128::ONE);
286 assert_eq!(result.unwrap(), I128::ONE);
287
288 let result = I128::ONE.checked_mul(&I128::MAX);
289 assert_eq!(result.unwrap(), I128::MAX);
290
291 let result = I128::MAX.checked_mul(&I128::MIN);
294 assert!(bool::from(result.is_none()));
295
296 let result = I128::MAX.checked_mul(&I128::MINUS_ONE);
297 assert_eq!(result.unwrap(), min_plus_one);
298
299 let result = I128::MAX.checked_mul(&I128::ZERO);
300 assert_eq!(result.unwrap(), I128::ZERO);
301
302 let result = I128::MAX.checked_mul(&I128::ONE);
303 assert_eq!(result.unwrap(), I128::MAX);
304
305 let result = I128::MAX.checked_mul(&I128::MAX);
306 assert!(bool::from(result.is_none()));
307 }
308
309 #[test]
310 fn test_wrapping_mul() {
311 let a = 0xFFFFFFFB7B63198EF870DF1F90D9BD9Eu128 as i128;
313 let b = 0xF20C29FA87B356AA3B4C05C4F9C24B4Au128 as i128;
314 let z = 0xAA700D354D6CF4EE881F8FF8093A19ACu128 as i128;
315 assert_eq!(a.wrapping_mul(b), z);
316 assert_eq!(
317 I128::from_i128(a).wrapping_mul(&I128::from_i128(b)),
318 I128::from_i128(z)
319 );
320
321 let c = -12345i64;
323 assert_eq!(
324 I128::from_i128(a).wrapping_mul(&I128::from_i64(c)),
325 I128::from_i128(a.wrapping_mul(i128::from(c)))
326 );
327
328 let a = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFu128 as i128;
330 assert!(!a.is_negative() && a.wrapping_mul(a).is_negative());
331
332 assert_eq!(i8::MAX.wrapping_mul(2), -2);
334 assert_eq!(i64::MAX.wrapping_mul(2), -2);
335 assert_eq!(
336 I128::MAX.wrapping_mul(&I128::from_i64(2i64)),
337 I128::from_i64(-2i64)
338 );
339
340 let x = -197044252290277702i64;
341 let y = -2631691865753118366;
342 let z = -2988283350644101836;
343 assert_eq!(x.wrapping_mul(y), z);
344 assert_eq!(
345 I64::from_i64(x).wrapping_mul(&I64::from_i64(y)),
346 I64::from_i64(z)
347 );
348
349 let x = -86027672844719838068326470675019902915i128;
350 let y = -21188806580823612823777395451044967239i128;
351 let z = 11054120842379932838712398402517374997i128;
352 assert_eq!(x.wrapping_mul(y), z);
353 assert_eq!(
354 I128::from_i128(x).wrapping_mul(&I128::from_i128(y)),
355 I128::from_i128(z)
356 );
357 }
358
359 #[test]
360 fn test_wrapping_mul_mixed() {
361 let a = U64::from_u64(0x0011223344556677);
362 let b = U128::from_u128(0x8899aabbccddeeff_8899aabbccddeeff);
363 let expected = a.as_int().concatenating_mul(b.as_int());
364 assert_eq!(a.as_int().wrapping_mul(b.as_int()), expected.resize());
365 assert_eq!(b.as_int().wrapping_mul(a.as_int()), expected.resize());
366 assert_eq!(
367 a.as_int().wrapping_neg().wrapping_mul(b.as_int()),
368 expected.wrapping_neg().resize()
369 );
370 assert_eq!(
371 a.as_int().wrapping_mul(&b.as_int().wrapping_neg()),
372 expected.wrapping_neg().resize()
373 );
374 assert_eq!(
375 b.as_int().wrapping_neg().wrapping_mul(a.as_int()),
376 expected.wrapping_neg().resize()
377 );
378 assert_eq!(
379 b.as_int().wrapping_mul(&a.as_int().wrapping_neg()),
380 expected.wrapping_neg().resize()
381 );
382 assert_eq!(
383 a.as_int()
384 .wrapping_neg()
385 .wrapping_mul(&b.as_int().wrapping_neg()),
386 expected.resize()
387 );
388 assert_eq!(
389 b.as_int()
390 .wrapping_neg()
391 .wrapping_mul(&a.as_int().wrapping_neg()),
392 expected.resize()
393 );
394 }
395
396 #[test]
397 fn test_saturating_mul() {
398 let a = 0xFFFFFFFB7B63198EF870DF1F90D9BD9Eu128 as i128;
400 let b = 0xF20C29FA87B356AA3B4C05C4F9C24B4Au128 as i128;
401 assert_eq!(a.saturating_mul(b), i128::MAX);
402 assert_eq!(
403 I128::from_i128(a).saturating_mul(&I128::from_i128(b)),
404 I128::MAX
405 );
406
407 let c = -12345i64;
409 assert_eq!(
410 I128::from_i128(a).saturating_mul(&I128::from_i64(c)),
411 I128::from_i128(a.saturating_mul(i128::from(c)))
412 );
413
414 assert_eq!(i8::MAX.saturating_mul(2), i8::MAX);
416 assert_eq!(i8::MAX.saturating_mul(-2), i8::MIN);
417 assert_eq!(i64::MAX.saturating_mul(2), i64::MAX);
418 assert_eq!(i64::MAX.saturating_mul(-2), i64::MIN);
419 assert_eq!(I128::MAX.saturating_mul(&I128::from_i64(2i64)), I128::MAX);
420 assert_eq!(I128::MAX.saturating_mul(&I128::from_i64(-2i64)), I128::MIN);
421
422 let x = -197044252290277702i64;
423 let y = -2631691865753118366;
424 assert_eq!(x.saturating_mul(y), i64::MAX);
425 assert_eq!(I64::from_i64(x).saturating_mul(&I64::from_i64(y)), I64::MAX);
426
427 let x = -86027672844719838068326470675019902915i128;
428 let y = 21188806580823612823777395451044967239i128;
429 assert_eq!(x.saturating_mul(y), i128::MIN);
430 assert_eq!(x.saturating_mul(-y), i128::MAX);
431 assert_eq!(
432 I128::from_i128(x).saturating_mul(&I128::from_i128(y)),
433 I128::MIN
434 );
435 assert_eq!(
436 I128::from_i128(x).saturating_mul(&I128::from_i128(-y)),
437 I128::MAX
438 );
439 }
440
441 #[test]
442 fn test_concatenating_mul() {
443 assert_eq!(
444 I128::MIN.concatenating_mul(&I128::MIN),
445 I256::from_be_hex("4000000000000000000000000000000000000000000000000000000000000000")
446 );
447 assert_eq!(
448 I128::MIN.concatenating_mul(&I128::MINUS_ONE),
449 I256::from_be_hex("0000000000000000000000000000000080000000000000000000000000000000")
450 );
451 assert_eq!(I128::MIN.concatenating_mul(&I128::ZERO), I256::ZERO);
452 assert_eq!(
453 I128::MIN.concatenating_mul(&I128::ONE),
454 I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80000000000000000000000000000000")
455 );
456 assert_eq!(
457 I128::MIN.concatenating_mul(&I128::MAX),
458 I256::from_be_hex("C000000000000000000000000000000080000000000000000000000000000000")
459 );
460
461 assert_eq!(
462 I128::MINUS_ONE.concatenating_mul(&I128::MIN),
463 I256::from_be_hex("0000000000000000000000000000000080000000000000000000000000000000")
464 );
465 assert_eq!(
466 I128::MINUS_ONE.concatenating_mul(&I128::MINUS_ONE),
467 I256::ONE
468 );
469 assert_eq!(I128::MINUS_ONE.concatenating_mul(&I128::ZERO), I256::ZERO);
470 assert_eq!(
471 I128::MINUS_ONE.concatenating_mul(&I128::ONE),
472 I256::MINUS_ONE
473 );
474 assert_eq!(
475 I128::MINUS_ONE.concatenating_mul(&I128::MAX),
476 I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80000000000000000000000000000001")
477 );
478
479 assert_eq!(I128::ZERO.concatenating_mul(&I128::MIN), I256::ZERO);
480 assert_eq!(I128::ZERO.concatenating_mul(&I128::MINUS_ONE), I256::ZERO);
481 assert_eq!(I128::ZERO.concatenating_mul(&I128::ZERO), I256::ZERO);
482 assert_eq!(I128::ZERO.concatenating_mul(&I128::ONE), I256::ZERO);
483 assert_eq!(I128::ZERO.concatenating_mul(&I128::MAX), I256::ZERO);
484
485 assert_eq!(
486 I128::ONE.concatenating_mul(&I128::MIN),
487 I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80000000000000000000000000000000")
488 );
489 assert_eq!(
490 I128::ONE.concatenating_mul(&I128::MINUS_ONE),
491 I256::MINUS_ONE
492 );
493 assert_eq!(I128::ONE.concatenating_mul(&I128::ZERO), I256::ZERO);
494 assert_eq!(I128::ONE.concatenating_mul(&I128::ONE), I256::ONE);
495 assert_eq!(
496 I128::ONE.concatenating_mul(&I128::MAX),
497 I256::from_be_hex("000000000000000000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
498 );
499
500 assert_eq!(
501 I128::MAX.concatenating_mul(&I128::MIN),
502 I256::from_be_hex("C000000000000000000000000000000080000000000000000000000000000000")
503 );
504 assert_eq!(
505 I128::MAX.concatenating_mul(&I128::MINUS_ONE),
506 I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80000000000000000000000000000001")
507 );
508 assert_eq!(I128::MAX.concatenating_mul(&I128::ZERO), I256::ZERO);
509 assert_eq!(
510 I128::MAX.concatenating_mul(&I128::ONE),
511 I256::from_be_hex("000000000000000000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
512 );
513 assert_eq!(
514 I128::MAX.concatenating_mul(&I128::MAX),
515 I256::from_be_hex("3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000001")
516 );
517 }
518
519 #[test]
520 fn test_concatenating_square() {
521 let res = I128::from_i64(i64::MIN).concatenating_square();
522 assert_eq!(
523 res,
524 U256::from_be_hex("0000000000000000000000000000000040000000000000000000000000000000")
525 );
526
527 let x: I128 = I128::MINUS_ONE << 64;
528 let res = x.concatenating_square();
529 assert_eq!(
530 res,
531 U256::from_be_hex("0000000000000000000000000000000100000000000000000000000000000000")
532 );
533 }
534
535 #[test]
536 fn test_checked_square() {
537 let res = I128::from_i64(i64::MIN).checked_square();
538 assert!(res.is_some().to_bool());
539 assert_eq!(
540 res.unwrap(),
541 U128::from_be_hex("40000000000000000000000000000000")
542 );
543
544 let x: I128 = I128::MINUS_ONE << 64;
545 let res = x.checked_square();
546 assert!(res.is_none().to_bool());
547 }
548
549 #[test]
550 fn test_wrapping_square() {
551 let res = I128::from_i64(i64::MIN).wrapping_square();
552 assert_eq!(res, U128::from_be_hex("40000000000000000000000000000000"));
553
554 let x: I128 = I128::MINUS_ONE << 64;
555 let res = x.wrapping_square();
556 assert_eq!(res, U128::ZERO);
557
558 let x: I128 = I128::from_i64(i64::MAX);
559 let res = x.wrapping_square();
560 assert_eq!(res, U128::from_be_hex("3FFFFFFFFFFFFFFF0000000000000001"));
561 }
562
563 #[test]
564 fn test_saturating_square() {
565 assert_eq!(
566 I128::from_i64(i64::MIN).saturating_square(),
567 U128::from_be_hex("40000000000000000000000000000000")
568 );
569 let x: I128 = I128::MINUS_ONE << 64;
570 assert_eq!(x.saturating_square(), U128::MAX);
571 }
572}