github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/examples/gno.land/p/demo/int256/bitwise.gno (about) 1 package int256 2 3 import ( 4 "gno.land/p/demo/uint256" 5 ) 6 7 // Or sets z = x | y and returns z. 8 func (z *Int) Or(x, y *Int) *Int { 9 if x.neg == y.neg { 10 if x.neg { 11 // (-x) | (-y) == ^(x-1) | ^(y-1) == ^((x-1) & (y-1)) == -(((x-1) & (y-1)) + 1) 12 x1 := new(uint256.Uint).Sub(x.abs, one) 13 y1 := new(uint256.Uint).Sub(y.abs, one) 14 z.abs = z.abs.Add(z.abs.And(x1, y1), one) 15 z.neg = true // z cannot be zero if x and y are negative 16 return z 17 } 18 19 // x | y == x | y 20 z.abs = z.abs.Or(x.abs, y.abs) 21 z.neg = false 22 return z 23 } 24 25 // x.neg != y.neg 26 if x.neg { 27 x, y = y, x // | is symmetric 28 } 29 30 // x | (-y) == x | ^(y-1) == ^((y-1) &^ x) == -(^((y-1) &^ x) + 1) 31 y1 := new(uint256.Uint).Sub(y.abs, one) 32 z.abs = z.abs.Add(z.abs.AndNot(y1, x.abs), one) 33 z.neg = true // z cannot be zero if one of x or y is negative 34 35 return z 36 } 37 38 // And sets z = x & y and returns z. 39 func (z *Int) And(x, y *Int) *Int { 40 if x.neg == y.neg { 41 if x.neg { 42 // (-x) & (-y) == ^(x-1) & ^(y-1) == ^((x-1) | (y-1)) == -(((x-1) | (y-1)) + 1) 43 x1 := new(uint256.Uint).Sub(x.abs, one) 44 y1 := new(uint256.Uint).Sub(y.abs, one) 45 z.abs = z.abs.Add(z.abs.Or(x1, y1), one) 46 z.neg = true // z cannot be zero if x and y are negative 47 return z 48 } 49 50 // x & y == x & y 51 z.abs = z.abs.And(x.abs, y.abs) 52 z.neg = false 53 return z 54 } 55 56 // x.neg != y.neg 57 // REF: https://cs.opensource.google/go/go/+/refs/tags/go1.22.1:src/math/big/int.go;l=1192-1202;drc=d57303e65f00b84b528ee682747dbe1fd3316d30 58 if x.neg { 59 x, y = y, x // & is symmetric 60 } 61 62 // x & (-y) == x & ^(y-1) == x &^ (y-1) 63 y1 := new(uint256.Uint).Sub(y.abs, uint256.One()) 64 z.abs = z.abs.AndNot(x.abs, y1) 65 z.neg = false 66 return z 67 } 68 69 // Rsh sets z = x >> n and returns z. 70 // OBS: Different from original implementation it was using math.Big 71 func (z *Int) Rsh(x *Int, n uint) *Int { 72 if !x.neg { 73 z.abs.Rsh(x.abs, n) 74 z.neg = x.neg 75 return z 76 } 77 78 // REF: https://cs.opensource.google/go/go/+/refs/tags/go1.22.1:src/math/big/int.go;l=1118-1126;drc=d57303e65f00b84b528ee682747dbe1fd3316d30 79 t := NewInt(0).Sub(FromUint256(x.abs), NewInt(1)) 80 t = t.Rsh(t, n) 81 82 _tmp := t.Add(t, NewInt(1)) 83 z.abs = _tmp.Abs() 84 z.neg = true 85 86 return z 87 } 88 89 // Lsh sets z = x << n and returns z. 90 func (z *Int) Lsh(x *Int, n uint) *Int { 91 z.abs.Lsh(x.abs, n) 92 z.neg = x.neg 93 return z 94 }