@@ -901,26 +901,46 @@ macro_rules! int_impl {
901
901
#[ rustc_const_stable( feature = "const_int_pow" , since = "1.50.0" ) ]
902
902
#[ must_use = "this returns the result of the operation, \
903
903
without modifying the original"]
904
+ #[ rustc_allow_const_fn_unstable( is_val_statically_known) ]
904
905
#[ inline]
905
906
pub const fn checked_pow( self , mut exp: u32 ) -> Option <Self > {
906
- if exp == 0 {
907
- return Some ( 1 ) ;
908
- }
909
- let mut base = self ;
910
- let mut acc: Self = 1 ;
907
+ // SAFETY: This path has the same behavior as the other.
908
+ if unsafe { intrinsics:: is_val_statically_known( self ) }
909
+ && self . unsigned_abs( ) . is_power_of_two( )
910
+ {
911
+ // SAFETY: We just checked this is a power of two. and above zero.
912
+ let power_used = unsafe { intrinsics:: cttz_nonzero( self . wrapping_abs( ) ) as u32 } ;
913
+ let num_shl = power_used. saturating_mul( exp) ;
914
+ let res = try_opt!( ( 1 as Self ) . checked_shl( num_shl) ) ;
915
+
916
+ let sign = self . is_negative( ) && exp & 1 != 0 ;
917
+ if !sign && res == Self :: MIN {
918
+ None
919
+ } else if sign {
920
+ Some ( res. wrapping_neg( ) )
921
+ } else {
922
+ Some ( res)
923
+ }
924
+ } else {
925
+ if exp == 0 {
926
+ return Some ( 1 ) ;
927
+ }
928
+ let mut base = self ;
929
+ let mut acc: Self = 1 ;
911
930
912
- while exp > 1 {
913
- if ( exp & 1 ) == 1 {
914
- acc = try_opt!( acc. checked_mul( base) ) ;
931
+ while exp > 1 {
932
+ if ( exp & 1 ) == 1 {
933
+ acc = try_opt!( acc. checked_mul( base) ) ;
934
+ }
935
+ exp /= 2 ;
936
+ base = try_opt!( base. checked_mul( base) ) ;
915
937
}
916
- exp /= 2 ;
917
- base = try_opt!( base. checked_mul( base) ) ;
938
+ // since exp!=0, finally the exp must be 1.
939
+ // Deal with the final bit of the exponent separately, since
940
+ // squaring the base afterwards is not necessary and may cause a
941
+ // needless overflow.
942
+ acc. checked_mul( base)
918
943
}
919
- // since exp!=0, finally the exp must be 1.
920
- // Deal with the final bit of the exponent separately, since
921
- // squaring the base afterwards is not necessary and may cause a
922
- // needless overflow.
923
- acc. checked_mul( base)
924
944
}
925
945
926
946
/// Returns the square root of the number, rounded down.
@@ -1537,27 +1557,48 @@ macro_rules! int_impl {
1537
1557
#[ rustc_const_stable( feature = "const_int_pow" , since = "1.50.0" ) ]
1538
1558
#[ must_use = "this returns the result of the operation, \
1539
1559
without modifying the original"]
1560
+ #[ rustc_allow_const_fn_unstable( is_val_statically_known) ]
1540
1561
#[ inline]
1541
1562
pub const fn wrapping_pow( self , mut exp: u32 ) -> Self {
1542
- if exp == 0 {
1543
- return 1 ;
1544
- }
1545
- let mut base = self ;
1546
- let mut acc: Self = 1 ;
1563
+ // SAFETY: This path has the same behavior as the other.
1564
+ if unsafe { intrinsics:: is_val_statically_known( self ) }
1565
+ && self . unsigned_abs( ) . is_power_of_two( )
1566
+ {
1567
+ // SAFETY: We just checked this is a power of two. and above zero.
1568
+ let power_used = unsafe { intrinsics:: cttz_nonzero( self . wrapping_abs( ) ) as u32 } ;
1569
+ let num_shl = power_used. saturating_mul( exp) ;
1570
+ let res = match ( 1 as Self ) . checked_shl( num_shl) {
1571
+ Some ( x) => x,
1572
+ None => 0
1573
+ } ;
1547
1574
1548
- while exp > 1 {
1549
- if ( exp & 1 ) == 1 {
1550
- acc = acc. wrapping_mul( base) ;
1575
+ let sign = self . is_negative( ) && exp & 1 != 0 ;
1576
+ if sign {
1577
+ res. wrapping_neg( )
1578
+ } else {
1579
+ res
1551
1580
}
1552
- exp /= 2 ;
1553
- base = base. wrapping_mul( base) ;
1554
- }
1581
+ } else {
1582
+ if exp == 0 {
1583
+ return 1 ;
1584
+ }
1585
+ let mut base = self ;
1586
+ let mut acc: Self = 1 ;
1555
1587
1556
- // since exp!=0, finally the exp must be 1.
1557
- // Deal with the final bit of the exponent separately, since
1558
- // squaring the base afterwards is not necessary and may cause a
1559
- // needless overflow.
1560
- acc. wrapping_mul( base)
1588
+ while exp > 1 {
1589
+ if ( exp & 1 ) == 1 {
1590
+ acc = acc. wrapping_mul( base) ;
1591
+ }
1592
+ exp /= 2 ;
1593
+ base = base. wrapping_mul( base) ;
1594
+ }
1595
+
1596
+ // since exp!=0, finally the exp must be 1.
1597
+ // Deal with the final bit of the exponent separately, since
1598
+ // squaring the base afterwards is not necessary and may cause a
1599
+ // needless overflow.
1600
+ acc. wrapping_mul( base)
1601
+ }
1561
1602
}
1562
1603
1563
1604
/// Calculates `self` + `rhs`
@@ -2039,36 +2080,58 @@ macro_rules! int_impl {
2039
2080
#[ rustc_const_stable( feature = "const_int_pow" , since = "1.50.0" ) ]
2040
2081
#[ must_use = "this returns the result of the operation, \
2041
2082
without modifying the original"]
2083
+ #[ rustc_allow_const_fn_unstable( is_val_statically_known) ]
2042
2084
#[ inline]
2043
2085
pub const fn overflowing_pow( self , mut exp: u32 ) -> ( Self , bool ) {
2044
- if exp == 0 {
2045
- return ( 1 , false ) ;
2046
- }
2047
- let mut base = self ;
2048
- let mut acc: Self = 1 ;
2049
- let mut overflown = false ;
2050
- // Scratch space for storing results of overflowing_mul.
2051
- let mut r;
2052
-
2053
- while exp > 1 {
2054
- if ( exp & 1 ) == 1 {
2055
- r = acc. overflowing_mul( base) ;
2056
- acc = r. 0 ;
2086
+ // SAFETY: This path has the same behavior as the other.
2087
+ if unsafe { intrinsics:: is_val_statically_known( self ) }
2088
+ && self . unsigned_abs( ) . is_power_of_two( )
2089
+ {
2090
+ // SAFETY: We just checked this is a power of two. and above zero.
2091
+ let power_used = unsafe { intrinsics:: cttz_nonzero( self . wrapping_abs( ) ) as u32 } ;
2092
+ let num_shl = power_used. saturating_mul( exp) ;
2093
+ let res = match ( 1 as Self ) . checked_shl( num_shl) {
2094
+ Some ( x) => x,
2095
+ None => 0
2096
+ } ;
2097
+
2098
+ let sign = self . is_negative( ) && exp & 1 != 0 ;
2099
+ let overflow = res == 0 || ( sign && res == Self :: MIN ) ;
2100
+ if sign {
2101
+ ( res. wrapping_neg( ) , overflow)
2102
+ } else {
2103
+ ( res, overflow)
2104
+ }
2105
+ } else {
2106
+ if exp == 0 {
2107
+ return ( 1 , false ) ;
2108
+ }
2109
+ let mut base = self ;
2110
+ let mut acc: Self = 1 ;
2111
+ let mut overflown = false ;
2112
+ // Scratch space for storing results of overflowing_mul.
2113
+ let mut r;
2114
+
2115
+ while exp > 1 {
2116
+ if ( exp & 1 ) == 1 {
2117
+ r = acc. overflowing_mul( base) ;
2118
+ acc = r. 0 ;
2119
+ overflown |= r. 1 ;
2120
+ }
2121
+ exp /= 2 ;
2122
+ r = base. overflowing_mul( base) ;
2123
+ base = r. 0 ;
2057
2124
overflown |= r. 1 ;
2058
2125
}
2059
- exp /= 2 ;
2060
- r = base. overflowing_mul( base) ;
2061
- base = r. 0 ;
2062
- overflown |= r. 1 ;
2063
- }
2064
2126
2065
- // since exp!=0, finally the exp must be 1.
2066
- // Deal with the final bit of the exponent separately, since
2067
- // squaring the base afterwards is not necessary and may cause a
2068
- // needless overflow.
2069
- r = acc. overflowing_mul( base) ;
2070
- r. 1 |= overflown;
2071
- r
2127
+ // since exp!=0, finally the exp must be 1.
2128
+ // Deal with the final bit of the exponent separately, since
2129
+ // squaring the base afterwards is not necessary and may cause a
2130
+ // needless overflow.
2131
+ r = acc. overflowing_mul( base) ;
2132
+ r. 1 |= overflown;
2133
+ r
2134
+ }
2072
2135
}
2073
2136
2074
2137
/// Raises self to the power of `exp`, using exponentiation by squaring.
@@ -2086,30 +2149,34 @@ macro_rules! int_impl {
2086
2149
#[ rustc_const_stable( feature = "const_int_pow" , since = "1.50.0" ) ]
2087
2150
#[ must_use = "this returns the result of the operation, \
2088
2151
without modifying the original"]
2152
+ #[ rustc_allow_const_fn_unstable( is_val_statically_known) ]
2089
2153
#[ inline]
2090
2154
#[ rustc_inherit_overflow_checks]
2091
2155
#[ track_caller] // Hides the hackish overflow check for powers of two.
2092
- #[ rustc_allow_const_fn_unstable( is_val_statically_known) ]
2093
2156
pub const fn pow( self , mut exp: u32 ) -> Self {
2094
2157
// SAFETY: This path has the same behavior as the other.
2095
2158
if unsafe { intrinsics:: is_val_statically_known( self ) }
2096
- && self > 0
2097
- && ( self & ( self - 1 ) == 0 )
2159
+ && self . unsigned_abs( ) . is_power_of_two( )
2098
2160
{
2099
2161
// SAFETY: We just checked this is a power of two. and above zero.
2100
- let power_used = unsafe { intrinsics:: cttz_nonzero( self ) as u32 } ;
2162
+ let power_used = unsafe { intrinsics:: cttz_nonzero( self . wrapping_abs ( ) ) as u32 } ;
2101
2163
let num_shl = power_used. saturating_mul( exp) ;
2102
2164
let res = match ( 1 as Self ) . checked_shl( num_shl) {
2103
2165
Some ( x) => x,
2104
2166
None => 0
2105
2167
} ;
2106
2168
2169
+ let sign = self . is_negative( ) && exp & 1 != 0 ;
2107
2170
#[ allow( arithmetic_overflow) ]
2108
- if res <= 0 {
2171
+ if res == 0 || ( !sign && res == Self :: MIN ) {
2109
2172
// So it panics.
2110
2173
_ = Self :: MAX * Self :: MAX ;
2111
2174
}
2112
- res
2175
+ if sign {
2176
+ res. wrapping_neg( )
2177
+ } else {
2178
+ res
2179
+ }
2113
2180
} else {
2114
2181
if exp == 0 {
2115
2182
return 1 ;
0 commit comments