github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/examples/gno.land/p/demo/int256/arithmetic.gno (about) 1 package int256 2 3 import ( 4 "gno.land/p/demo/uint256" 5 ) 6 7 func (z *Int) Add(x, y *Int) *Int { 8 z.initiateAbs() 9 10 neg := x.neg 11 12 if x.neg == y.neg { 13 // x + y == x + y 14 // (-x) + (-y) == -(x + y) 15 z.abs = z.abs.Add(x.abs, y.abs) 16 } else { 17 // x + (-y) == x - y == -(y - x) 18 // (-x) + y == y - x == -(x - y) 19 if x.abs.Cmp(y.abs) >= 0 { 20 z.abs = z.abs.Sub(x.abs, y.abs) 21 } else { 22 neg = !neg 23 z.abs = z.abs.Sub(y.abs, x.abs) 24 } 25 } 26 z.neg = neg // 0 has no sign 27 return z 28 } 29 30 // AddUint256 set z to the sum x + y, where y is a uint256, and returns z 31 func (z *Int) AddUint256(x *Int, y *uint256.Uint) *Int { 32 if x.neg { 33 if x.abs.Gt(y) { 34 z.abs.Sub(x.abs, y) 35 z.neg = true 36 } else { 37 z.abs.Sub(y, x.abs) 38 z.neg = false 39 } 40 } else { 41 z.abs.Add(x.abs, y) 42 z.neg = false 43 } 44 return z 45 } 46 47 // Sets z to the sum x + y, where z and x are uint256s and y is an int256. 48 func AddDelta(z, x *uint256.Uint, y *Int) { 49 if y.neg { 50 z.Sub(x, y.abs) 51 } else { 52 z.Add(x, y.abs) 53 } 54 } 55 56 // Sets z to the sum x + y, where z and x are uint256s and y is an int256. 57 func AddDeltaOverflow(z, x *uint256.Uint, y *Int) bool { 58 var overflow bool 59 if y.neg { 60 _, overflow = z.SubOverflow(x, y.abs) 61 } else { 62 _, overflow = z.AddOverflow(x, y.abs) 63 } 64 return overflow 65 } 66 67 // Sub sets z to the difference x-y and returns z. 68 func (z *Int) Sub(x, y *Int) *Int { 69 z.initiateAbs() 70 71 neg := x.neg 72 if x.neg != y.neg { 73 // x - (-y) == x + y 74 // (-x) - y == -(x + y) 75 z.abs = z.abs.Add(x.abs, y.abs) 76 } else { 77 // x - y == x - y == -(y - x) 78 // (-x) - (-y) == y - x == -(x - y) 79 if x.abs.Cmp(y.abs) >= 0 { 80 z.abs = z.abs.Sub(x.abs, y.abs) 81 } else { 82 neg = !neg 83 z.abs = z.abs.Sub(y.abs, x.abs) 84 } 85 } 86 z.neg = neg // 0 has no sign 87 return z 88 } 89 90 // SubUint256 set z to the difference x - y, where y is a uint256, and returns z 91 func (z *Int) SubUint256(x *Int, y *uint256.Uint) *Int { 92 if x.neg { 93 z.abs.Add(x.abs, y) 94 z.neg = true 95 } else { 96 if x.abs.Lt(y) { 97 z.abs.Sub(y, x.abs) 98 z.neg = true 99 } else { 100 z.abs.Sub(x.abs, y) 101 z.neg = false 102 } 103 } 104 return z 105 } 106 107 // Mul sets z to the product x*y and returns z. 108 func (z *Int) Mul(x, y *Int) *Int { 109 z.initiateAbs() 110 111 z.abs = z.abs.Mul(x.abs, y.abs) 112 z.neg = x.neg != y.neg // 0 has no sign 113 return z 114 } 115 116 // MulUint256 sets z to the product x*y, where y is a uint256, and returns z 117 func (z *Int) MulUint256(x *Int, y *uint256.Uint) *Int { 118 z.abs.Mul(x.abs, y) 119 if z.abs.IsZero() { 120 z.neg = false 121 } else { 122 z.neg = x.neg 123 } 124 return z 125 } 126 127 // Div sets z to the quotient x/y for y != 0 and returns z. 128 func (z *Int) Div(x, y *Int) *Int { 129 z.initiateAbs() 130 131 z.abs.Div(x.abs, y.abs) 132 if x.neg == y.neg { 133 z.neg = false 134 } else { 135 z.neg = true 136 } 137 return z 138 } 139 140 // DivUint256 sets z to the quotient x/y, where y is a uint256, and returns z 141 // If y == 0, z is set to 0 142 func (z *Int) DivUint256(x *Int, y *uint256.Uint) *Int { 143 z.abs.Div(x.abs, y) 144 if z.abs.IsZero() { 145 z.neg = false 146 } else { 147 z.neg = x.neg 148 } 149 return z 150 } 151 152 // Quo sets z to the quotient x/y for y != 0 and returns z. 153 // If y == 0, a division-by-zero run-time panic occurs. 154 // OBS: differs from mempooler int256, we need to panic manually if y == 0 155 // Quo implements truncated division (like Go); see QuoRem for more details. 156 func (z *Int) Quo(x, y *Int) *Int { 157 if y.IsZero() { 158 panic("division by zero") 159 } 160 161 z.initiateAbs() 162 163 z.abs = z.abs.Div(x.abs, y.abs) 164 z.neg = !(z.abs.IsZero()) && x.neg != y.neg // 0 has no sign 165 return z 166 } 167 168 // Rem sets z to the remainder x%y for y != 0 and returns z. 169 // If y == 0, a division-by-zero run-time panic occurs. 170 // OBS: differs from mempooler int256, we need to panic manually if y == 0 171 // Rem implements truncated modulus (like Go); see QuoRem for more details. 172 func (z *Int) Rem(x, y *Int) *Int { 173 if y.IsZero() { 174 panic("division by zero") 175 } 176 177 z.initiateAbs() 178 179 z.abs.Mod(x.abs, y.abs) 180 z.neg = z.abs.Sign() > 0 && x.neg // 0 has no sign 181 return z 182 } 183 184 // Mod sets z to the modulus x%y for y != 0 and returns z. 185 // If y == 0, z is set to 0 (OBS: differs from the big.Int) 186 func (z *Int) Mod(x, y *Int) *Int { 187 if x.neg { 188 z.abs.Div(x.abs, y.abs) 189 z.abs.Add(z.abs, one) 190 z.abs.Mul(z.abs, y.abs) 191 z.abs.Sub(z.abs, x.abs) 192 z.abs.Mod(z.abs, y.abs) 193 } else { 194 z.abs.Mod(x.abs, y.abs) 195 } 196 z.neg = false 197 return z 198 }