@@ -77,6 +77,19 @@ impl<const LIMBS: usize> Int<LIMBS> {
7777 Self :: new_from_abs_sign ( * lo, lhs_sgn. xor ( rhs_sgn) ) . and_choice ( is_some)
7878 }
7979
80+ /// Multiply `self` by `rhs`, saturating at the numeric bounds instead of overflowing.
81+ pub const fn saturating_mul < const RHS_LIMBS : usize > ( & self , rhs : & Int < RHS_LIMBS > ) -> Self {
82+ let ( abs_lhs, lhs_sgn) = self . abs_sign ( ) ;
83+ let ( abs_rhs, rhs_sgn) = rhs. abs_sign ( ) ;
84+ let maybe_res = abs_lhs. checked_mul ( & abs_rhs) ;
85+ let ( lo, is_some) = maybe_res. components_ref ( ) ;
86+ let is_neg = lhs_sgn. xor ( rhs_sgn) ;
87+ let bound = Self :: select ( & Self :: MAX , & Self :: MIN , is_neg) ;
88+ Self :: new_from_abs_sign ( * lo, is_neg)
89+ . and_choice ( is_some)
90+ . unwrap_or ( bound)
91+ }
92+
8093 /// Multiply `self` by `rhs`, wrapping the result in case of overflow.
8194 /// This is equivalent to `(self * rhs) % (Uint::<LIMBS>::MAX + 1)`.
8295 pub const fn wrapping_mul < const RHS_LIMBS : usize > ( & self , rhs : & Int < RHS_LIMBS > ) -> Self {
@@ -330,6 +343,51 @@ mod tests {
330343 ) ;
331344 }
332345
346+ #[ test]
347+ fn test_saturating_mul ( ) {
348+ // wrapping
349+ let a = 0xFFFFFFFB7B63198EF870DF1F90D9BD9Eu128 as i128 ;
350+ let b = 0xF20C29FA87B356AA3B4C05C4F9C24B4Au128 as i128 ;
351+ assert_eq ! ( a. saturating_mul( b) , i128 :: MAX ) ;
352+ assert_eq ! (
353+ I128 :: from_i128( a) . saturating_mul( & I128 :: from_i128( b) ) ,
354+ I128 :: MAX
355+ ) ;
356+
357+ // no wrapping
358+ let c = -12345i64 ;
359+ assert_eq ! (
360+ I128 :: from_i128( a) . saturating_mul( & I128 :: from_i64( c) ) ,
361+ I128 :: from_i128( a. saturating_mul( c as i128 ) )
362+ ) ;
363+
364+ // core case
365+ assert_eq ! ( i8 :: MAX . saturating_mul( 2 ) , i8 :: MAX ) ;
366+ assert_eq ! ( i8 :: MAX . saturating_mul( -2 ) , i8 :: MIN ) ;
367+ assert_eq ! ( i64 :: MAX . saturating_mul( 2 ) , i64 :: MAX ) ;
368+ assert_eq ! ( i64 :: MAX . saturating_mul( -2 ) , i64 :: MIN ) ;
369+ assert_eq ! ( I128 :: MAX . saturating_mul( & I128 :: from_i64( 2i64 ) ) , I128 :: MAX ) ;
370+ assert_eq ! ( I128 :: MAX . saturating_mul( & I128 :: from_i64( -2i64 ) ) , I128 :: MIN ) ;
371+
372+ let x = -197044252290277702i64 ;
373+ let y = -2631691865753118366 ;
374+ assert_eq ! ( x. saturating_mul( y) , i64 :: MAX ) ;
375+ assert_eq ! ( I64 :: from_i64( x) . saturating_mul( & I64 :: from_i64( y) ) , I64 :: MAX ) ;
376+
377+ let x = -86027672844719838068326470675019902915i128 ;
378+ let y = 21188806580823612823777395451044967239i128 ;
379+ assert_eq ! ( x. saturating_mul( y) , i128 :: MIN ) ;
380+ assert_eq ! ( x. saturating_mul( -y) , i128 :: MAX ) ;
381+ assert_eq ! (
382+ I128 :: from_i128( x) . saturating_mul( & I128 :: from_i128( y) ) ,
383+ I128 :: MIN
384+ ) ;
385+ assert_eq ! (
386+ I128 :: from_i128( x) . saturating_mul( & I128 :: from_i128( -y) ) ,
387+ I128 :: MAX
388+ ) ;
389+ }
390+
333391 #[ test]
334392 fn test_concatenating_mul ( ) {
335393 assert_eq ! (
0 commit comments