11use crate :: primitives:: U256 ;
22use core:: cmp:: Ordering ;
33
4- #[ cfg( test) ]
5- use proptest_derive:: Arbitrary as PropTestArbitrary ;
6-
7- #[ cfg( any( test, feature = "arbitrary" ) ) ]
8- use arbitrary:: Arbitrary ;
9-
10- #[ cfg_attr( test, derive( PropTestArbitrary ) ) ]
11- #[ cfg_attr( any( test, feature = "arbitrary" ) , derive( Arbitrary ) ) ]
12- #[ derive( Copy , Clone , Eq , PartialEq , Debug ) ]
13- pub enum Sign {
14- Plus ,
15- Minus ,
16- Zero ,
4+ #[ derive( Clone , Copy , PartialEq , Eq , PartialOrd , Ord ) ]
5+ #[ repr( i8 ) ]
6+ pub ( super ) enum Sign {
7+ // same as `cmp::Ordering`
8+ Minus = -1 ,
9+ Zero = 0 ,
10+ #[ allow( dead_code) ] // "constructed" with `mem::transmute` in `i256_sign` below
11+ Plus = 1 ,
1712}
1813
19- pub const _SIGN_BIT_MASK: U256 = U256 :: from_limbs ( [
20- 0xFFFFFFFFFFFFFFFF ,
21- 0xFFFFFFFFFFFFFFFF ,
22- 0xFFFFFFFFFFFFFFFF ,
23- 0x7FFFFFFFFFFFFFFF ,
24- ] ) ;
25- pub const MIN_NEGATIVE_VALUE : U256 = U256 :: from_limbs ( [
14+ const MIN_NEGATIVE_VALUE : U256 = U256 :: from_limbs ( [
2615 0x0000000000000000 ,
2716 0x0000000000000000 ,
2817 0x0000000000000000 ,
@@ -31,107 +20,99 @@ pub const MIN_NEGATIVE_VALUE: U256 = U256::from_limbs([
3120
3221const FLIPH_BITMASK_U64 : u64 = 0x7FFFFFFFFFFFFFFF ;
3322
34- #[ cfg_attr( test, derive( PropTestArbitrary ) ) ]
35- #[ cfg_attr( any( test, feature = "arbitrary" ) , derive( Arbitrary ) ) ]
36- #[ derive( Copy , Clone , Eq , PartialEq , Debug ) ]
37- pub struct I256 ( pub Sign , pub U256 ) ;
38-
3923#[ inline( always) ]
40- pub fn i256_sign < const DO_TWO_COMPL : bool > ( val : & mut U256 ) -> Sign {
41- if !val. bit ( U256 :: BITS - 1 ) {
42- if * val == U256 :: ZERO {
43- Sign :: Zero
44- } else {
45- Sign :: Plus
46- }
47- } else {
48- if DO_TWO_COMPL {
49- two_compl_mut ( val) ;
50- }
24+ pub ( super ) fn i256_sign ( val : & U256 ) -> Sign {
25+ if val. bit ( U256 :: BITS - 1 ) {
5126 Sign :: Minus
27+ } else {
28+ // SAFETY: false == 0 == Zero, true == 1 == Plus
29+ unsafe { core:: mem:: transmute ( * val != U256 :: ZERO ) }
30+ }
31+ }
32+
33+ #[ inline( always) ]
34+ pub ( super ) fn i256_sign_compl ( val : & mut U256 ) -> Sign {
35+ let sign = i256_sign ( val) ;
36+ if sign == Sign :: Minus {
37+ two_compl_mut ( val) ;
5238 }
39+ sign
5340}
5441
5542#[ inline( always) ]
5643fn u256_remove_sign ( val : & mut U256 ) {
44+ // SAFETY: U256 does not have any padding bytes
5745 unsafe {
5846 val. as_limbs_mut ( ) [ 3 ] &= FLIPH_BITMASK_U64 ;
5947 }
6048}
6149
6250#[ inline( always) ]
63- pub fn two_compl_mut ( op : & mut U256 ) {
51+ pub ( super ) fn two_compl_mut ( op : & mut U256 ) {
6452 * op = two_compl ( * op) ;
6553}
6654
67- pub fn two_compl ( op : U256 ) -> U256 {
55+ #[ inline( always) ]
56+ pub ( super ) fn two_compl ( op : U256 ) -> U256 {
6857 op. wrapping_neg ( )
6958}
7059
7160#[ inline( always) ]
72- pub fn i256_cmp ( mut first : U256 , mut second : U256 ) -> Ordering {
73- let first_sign = i256_sign :: < false > ( & mut first) ;
74- let second_sign = i256_sign :: < false > ( & mut second) ;
75- match ( first_sign, second_sign) {
76- ( Sign :: Zero , Sign :: Zero ) => Ordering :: Equal ,
77- ( Sign :: Zero , Sign :: Plus ) => Ordering :: Less ,
78- ( Sign :: Zero , Sign :: Minus ) => Ordering :: Greater ,
79- ( Sign :: Minus , Sign :: Zero ) => Ordering :: Less ,
80- ( Sign :: Minus , Sign :: Plus ) => Ordering :: Less ,
81- ( Sign :: Minus , Sign :: Minus ) => first. cmp ( & second) ,
82- ( Sign :: Plus , Sign :: Minus ) => Ordering :: Greater ,
83- ( Sign :: Plus , Sign :: Zero ) => Ordering :: Greater ,
84- ( Sign :: Plus , Sign :: Plus ) => first. cmp ( & second) ,
61+ pub ( super ) fn i256_cmp ( first : & U256 , second : & U256 ) -> Ordering {
62+ let first_sign = i256_sign ( first) ;
63+ let second_sign = i256_sign ( second) ;
64+ match first_sign. cmp ( & second_sign) {
65+ // note: adding `if first_sign != Sign::Zero` to short circuit zero comparisons performs
66+ // slower on average, as of #582
67+ Ordering :: Equal => first. cmp ( second) ,
68+ o => o,
8569 }
8670}
8771
8872#[ inline( always) ]
89- pub fn i256_div ( mut first : U256 , mut second : U256 ) -> U256 {
90- let second_sign = i256_sign :: < true > ( & mut second) ;
73+ pub ( super ) fn i256_div ( mut first : U256 , mut second : U256 ) -> U256 {
74+ let second_sign = i256_sign_compl ( & mut second) ;
9175 if second_sign == Sign :: Zero {
9276 return U256 :: ZERO ;
9377 }
94- let first_sign = i256_sign :: < true > ( & mut first) ;
78+
79+ let first_sign = i256_sign_compl ( & mut first) ;
9580 if first_sign == Sign :: Minus && first == MIN_NEGATIVE_VALUE && second == U256 :: from ( 1 ) {
9681 return two_compl ( MIN_NEGATIVE_VALUE ) ;
9782 }
9883
99- //let mut d = first / second;
100- let mut d = first. div_rem ( second) . 0 ;
84+ // necessary overflow checks are done above, perform the division
85+ let mut d = first / second;
10186
87+ // set sign bit to zero
10288 u256_remove_sign ( & mut d) ;
103- //set sign bit to zero
10489
105- if d == U256 :: ZERO {
106- return U256 :: ZERO ;
107- }
108-
109- match ( first_sign, second_sign) {
110- ( Sign :: Zero , Sign :: Plus )
111- | ( Sign :: Plus , Sign :: Zero )
112- | ( Sign :: Zero , Sign :: Zero )
113- | ( Sign :: Plus , Sign :: Plus )
114- | ( Sign :: Minus , Sign :: Minus ) => d,
115- ( Sign :: Zero , Sign :: Minus )
116- | ( Sign :: Plus , Sign :: Minus )
117- | ( Sign :: Minus , Sign :: Zero )
118- | ( Sign :: Minus , Sign :: Plus ) => two_compl ( d) ,
90+ // two's complement only if the signs are different
91+ // note: this condition has better codegen than an exhaustive match, as of #582
92+ if ( first_sign == Sign :: Minus && second_sign != Sign :: Minus )
93+ || ( second_sign == Sign :: Minus && first_sign != Sign :: Minus )
94+ {
95+ two_compl ( d)
96+ } else {
97+ d
11998 }
12099}
121100
122101#[ inline( always) ]
123- pub fn i256_mod ( mut first : U256 , mut second : U256 ) -> U256 {
124- let first_sign = i256_sign :: < true > ( & mut first) ;
102+ pub ( super ) fn i256_mod ( mut first : U256 , mut second : U256 ) -> U256 {
103+ let first_sign = i256_sign_compl ( & mut first) ;
125104 if first_sign == Sign :: Zero {
126105 return U256 :: ZERO ;
127106 }
128107
129- let _ = i256_sign :: < true > ( & mut second) ;
108+ let _ = i256_sign_compl ( & mut second) ;
109+
110+ // necessary overflow checks are done above, perform the operation
130111 let mut r = first % second;
112+
113+ // set sign bit to zero
131114 u256_remove_sign ( & mut r) ;
132- if r == U256 :: ZERO {
133- return U256 :: ZERO ;
134- }
115+
135116 if first_sign == Sign :: Minus {
136117 two_compl ( r)
137118 } else {
@@ -171,9 +152,4 @@ mod tests {
171152 assert_eq ! ( i256_div( one_hundred, minus_one) , neg_one_hundred) ;
172153 assert_eq ! ( i256_div( one_hundred, two) , fifty) ;
173154 }
174-
175- #[ test]
176- fn arbitrary ( ) {
177- proptest:: proptest!( |( _value: I256 ) | { } )
178- }
179155}
0 commit comments