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