@@ -591,7 +591,11 @@ impl Number {
591591 }
592592 }
593593 ( Number :: Int ( a) , Number :: Int ( b) ) => {
594- if * a % * b == 0 {
594+ if * a == i64:: MIN && * b == -1 {
595+ // Rust panics on i64::MIN % -1i64, so handle it specially
596+ let quotient = BigInt :: from ( * a) / BigInt :: from ( * b) ;
597+ Ok ( Number :: from_bigint_owned ( quotient) )
598+ } else if * a % * b == 0 {
595599 if let Some ( q) = a. checked_div ( * b) {
596600 Ok ( Number :: Int ( q) )
597601 } else {
@@ -991,3 +995,41 @@ fn scientific_parts_to_bigint(mantissa: &str, exponent: i32) -> Option<BigInt> {
991995
992996 Some ( value)
993997}
998+
999+ #[ cfg( test) ]
1000+ mod tests {
1001+ #![ allow( clippy:: expect_used) ] // tests expect() to assert arithmetic results
1002+
1003+ use super :: * ;
1004+
1005+ /// Regression test: `i64::MIN / -1` overflows `i64` and panics in Rust's
1006+ /// native integer division/remainder. `divide` must promote the result
1007+ /// instead of panicking.
1008+ #[ test]
1009+ fn i64_min_by_negative_one ( ) {
1010+ let quotient = Number :: Int ( i64:: MIN )
1011+ . divide ( & Number :: Int ( -1 ) )
1012+ . expect ( "division should succeed" ) ;
1013+
1014+ // 2^63 does not fit in i64, but does fit in u64.
1015+ assert_eq ! ( quotient. as_u64( ) , Some ( 9_223_372_036_854_775_808 ) ) ;
1016+ assert_eq ! ( quotient. as_i64( ) , None ) ;
1017+ assert_eq ! ( quotient. as_i128( ) , Some ( 9_223_372_036_854_775_808 ) ) ;
1018+ assert_eq ! (
1019+ * quotient. to_big( ) . expect( "to_big should succeed" ) ,
1020+ -BigInt :: from( i64 :: MIN )
1021+ ) ;
1022+
1023+ // The same overflow case reached via the mixed `Int`/`BigInt` path.
1024+ let big_quotient = Number :: Int ( i64:: MIN )
1025+ . divide ( & Number :: BigInt ( Rc :: new ( BigInt :: from ( -1 ) ) ) )
1026+ . expect ( "division should succeed" ) ;
1027+ assert_eq ! ( big_quotient. as_u64( ) , Some ( 9_223_372_036_854_775_808 ) ) ;
1028+
1029+ // `i64::MIN % -1` also panics natively; the result must be zero.
1030+ let remainder = Number :: Int ( i64:: MIN )
1031+ . modulo ( & Number :: Int ( -1 ) )
1032+ . expect ( "modulo should succeed" ) ;
1033+ assert_eq ! ( remainder. as_i64( ) , Some ( 0 ) ) ;
1034+ }
1035+ }
0 commit comments