github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/gnovm/stdlibs/math/overflow/overflow.gno (about) 1 // This is modified from https://github.com/JohnCGriffin/overflow (MIT). 2 // NOTE: there was a bug with the original Quotient* functions, and 3 // testing method. These have been fixed here, and tests ported to 4 // tests/files/maths_int*.go respectively. 5 // Note: moved over from p/demo/maths. 6 7 /* 8 Package overflow offers overflow-checked integer arithmetic operations 9 for int, int32, and int64. Each of the operations returns a 10 result,bool combination. This was prompted by the need to know when 11 to flow into higher precision types from the math.big library. 12 13 For instance, assuing a 64 bit machine: 14 15 10 + 20 -> 30 16 int(math.MaxInt64) + 1 -> -9223372036854775808 17 18 whereas 19 20 overflow.Add(10,20) -> (30, true) 21 overflow.Add(math.MaxInt64,1) -> (0, false) 22 23 Add, Sub, Mul, Div are for int. Add64, Add32, etc. are specifically sized. 24 25 If anybody wishes an unsigned version, submit a pull request for code 26 and new tests. 27 */ 28 package overflow 29 30 import "math" 31 32 //go:generate ./overflow_template.sh 33 34 func _is64Bit() bool { 35 maxU32 := uint(math.MaxUint32) 36 return ((maxU32 << 1) >> 1) == maxU32 37 } 38 39 /********** PARTIAL TEST COVERAGE FROM HERE DOWN ************* 40 41 The only way that I could see to do this is a combination of 42 my normal 64 bit system and a GopherJS running on Node. My 43 understanding is that its ints are 32 bit. 44 45 So, FEEL FREE to carefully review the code visually. 46 47 *************************************************************/ 48 49 // Unspecified size, i.e. normal signed int 50 51 // Add sums two ints, returning the result and a boolean status. 52 func Add(a, b int) (int, bool) { 53 if _is64Bit() { 54 r64, ok := Add64(int64(a), int64(b)) 55 return int(r64), ok 56 } 57 r32, ok := Add32(int32(a), int32(b)) 58 return int(r32), ok 59 } 60 61 // Sub returns the difference of two ints and a boolean status. 62 func Sub(a, b int) (int, bool) { 63 if _is64Bit() { 64 r64, ok := Sub64(int64(a), int64(b)) 65 return int(r64), ok 66 } 67 r32, ok := Sub32(int32(a), int32(b)) 68 return int(r32), ok 69 } 70 71 // Mul returns the product of two ints and a boolean status. 72 func Mul(a, b int) (int, bool) { 73 if _is64Bit() { 74 r64, ok := Mul64(int64(a), int64(b)) 75 return int(r64), ok 76 } 77 r32, ok := Mul32(int32(a), int32(b)) 78 return int(r32), ok 79 } 80 81 // Div returns the quotient of two ints and a boolean status 82 func Div(a, b int) (int, bool) { 83 if _is64Bit() { 84 r64, ok := Div64(int64(a), int64(b)) 85 return int(r64), ok 86 } 87 r32, ok := Div32(int32(a), int32(b)) 88 return int(r32), ok 89 } 90 91 // Quo returns the quotient, remainder and status of two ints 92 func Quo(a, b int) (int, int, bool) { 93 if _is64Bit() { 94 q64, r64, ok := Quo64(int64(a), int64(b)) 95 return int(q64), int(r64), ok 96 } 97 q32, r32, ok := Quo32(int32(a), int32(b)) 98 return int(q32), int(r32), ok 99 } 100 101 /************* Panic versions for int ****************/ 102 103 // Addp returns the sum of two ints, panicking on overflow 104 func Addp(a, b int) int { 105 r, ok := Add(a, b) 106 if !ok { 107 panic("addition overflow") 108 } 109 return r 110 } 111 112 // Subp returns the difference of two ints, panicking on overflow. 113 func Subp(a, b int) int { 114 r, ok := Sub(a, b) 115 if !ok { 116 panic("subtraction overflow") 117 } 118 return r 119 } 120 121 // Mulp returns the product of two ints, panicking on overflow. 122 func Mulp(a, b int) int { 123 r, ok := Mul(a, b) 124 if !ok { 125 panic("multiplication overflow") 126 } 127 return r 128 } 129 130 // Divp returns the quotient of two ints, panicking on overflow. 131 func Divp(a, b int) int { 132 r, ok := Div(a, b) 133 if !ok { 134 panic("division failure") 135 } 136 return r 137 } 138 139 //---------------------------------------- 140 // This is generated code, created by overflow_template.sh executed 141 // by "go generate" 142 143 // Add8 performs + operation on two int8 operands 144 // returning a result and status 145 func Add8(a, b int8) (int8, bool) { 146 c := a + b 147 if (c > a) == (b > 0) { 148 return c, true 149 } 150 return c, false 151 } 152 153 // Add8p is the unchecked panicking version of Add8 154 func Add8p(a, b int8) int8 { 155 r, ok := Add8(a, b) 156 if !ok { 157 panic("addition overflow") 158 } 159 return r 160 } 161 162 // Sub8 performs - operation on two int8 operands 163 // returning a result and status 164 func Sub8(a, b int8) (int8, bool) { 165 c := a - b 166 if (c < a) == (b > 0) { 167 return c, true 168 } 169 return c, false 170 } 171 172 // Sub8p is the unchecked panicking version of Sub8 173 func Sub8p(a, b int8) int8 { 174 r, ok := Sub8(a, b) 175 if !ok { 176 panic("subtraction overflow") 177 } 178 return r 179 } 180 181 // Mul8 performs * operation on two int8 operands 182 // returning a result and status 183 func Mul8(a, b int8) (int8, bool) { 184 if a == 0 || b == 0 { 185 return 0, true 186 } 187 c := a * b 188 if (c < 0) == ((a < 0) != (b < 0)) { 189 if c/b == a { 190 return c, true 191 } 192 } 193 return c, false 194 } 195 196 // Mul8p is the unchecked panicking version of Mul8 197 func Mul8p(a, b int8) int8 { 198 r, ok := Mul8(a, b) 199 if !ok { 200 panic("multiplication overflow") 201 } 202 return r 203 } 204 205 // Div8 performs / operation on two int8 operands 206 // returning a result and status 207 func Div8(a, b int8) (int8, bool) { 208 q, _, ok := Quo8(a, b) 209 return q, ok 210 } 211 212 // Div8p is the unchecked panicking version of Div8 213 func Div8p(a, b int8) int8 { 214 r, ok := Div8(a, b) 215 if !ok { 216 panic("division failure") 217 } 218 return r 219 } 220 221 // Quo8 performs + operation on two int8 operands 222 // returning a quotient, a remainder and status 223 func Quo8(a, b int8) (int8, int8, bool) { 224 if b == 0 { 225 return 0, 0, false 226 } else if b == -1 && a == math.MinInt8 { 227 return 0, 0, false 228 } 229 c := a / b 230 return c, a % b, true 231 } 232 233 // Add16 performs + operation on two int16 operands 234 // returning a result and status 235 func Add16(a, b int16) (int16, bool) { 236 c := a + b 237 if (c > a) == (b > 0) { 238 return c, true 239 } 240 return c, false 241 } 242 243 // Add16p is the unchecked panicking version of Add16 244 func Add16p(a, b int16) int16 { 245 r, ok := Add16(a, b) 246 if !ok { 247 panic("addition overflow") 248 } 249 return r 250 } 251 252 // Sub16 performs - operation on two int16 operands 253 // returning a result and status 254 func Sub16(a, b int16) (int16, bool) { 255 c := a - b 256 if (c < a) == (b > 0) { 257 return c, true 258 } 259 return c, false 260 } 261 262 // Sub16p is the unchecked panicking version of Sub16 263 func Sub16p(a, b int16) int16 { 264 r, ok := Sub16(a, b) 265 if !ok { 266 panic("subtraction overflow") 267 } 268 return r 269 } 270 271 // Mul16 performs * operation on two int16 operands 272 // returning a result and status 273 func Mul16(a, b int16) (int16, bool) { 274 if a == 0 || b == 0 { 275 return 0, true 276 } 277 c := a * b 278 if (c < 0) == ((a < 0) != (b < 0)) { 279 if c/b == a { 280 return c, true 281 } 282 } 283 return c, false 284 } 285 286 // Mul16p is the unchecked panicking version of Mul16 287 func Mul16p(a, b int16) int16 { 288 r, ok := Mul16(a, b) 289 if !ok { 290 panic("multiplication overflow") 291 } 292 return r 293 } 294 295 // Div16 performs / operation on two int16 operands 296 // returning a result and status 297 func Div16(a, b int16) (int16, bool) { 298 q, _, ok := Quo16(a, b) 299 return q, ok 300 } 301 302 // Div16p is the unchecked panicking version of Div16 303 func Div16p(a, b int16) int16 { 304 r, ok := Div16(a, b) 305 if !ok { 306 panic("division failure") 307 } 308 return r 309 } 310 311 // Quo16 performs + operation on two int16 operands 312 // returning a quotient, a remainder and status 313 func Quo16(a, b int16) (int16, int16, bool) { 314 if b == 0 { 315 return 0, 0, false 316 } else if b == -1 && a == math.MinInt16 { 317 return 0, 0, false 318 } 319 c := a / b 320 return c, a % b, true 321 } 322 323 // Add32 performs + operation on two int32 operands 324 // returning a result and status 325 func Add32(a, b int32) (int32, bool) { 326 c := a + b 327 if (c > a) == (b > 0) { 328 return c, true 329 } 330 return c, false 331 } 332 333 // Add32p is the unchecked panicking version of Add32 334 func Add32p(a, b int32) int32 { 335 r, ok := Add32(a, b) 336 if !ok { 337 panic("addition overflow") 338 } 339 return r 340 } 341 342 // Sub32 performs - operation on two int32 operands 343 // returning a result and status 344 func Sub32(a, b int32) (int32, bool) { 345 c := a - b 346 if (c < a) == (b > 0) { 347 return c, true 348 } 349 return c, false 350 } 351 352 // Sub32p is the unchecked panicking version of Sub32 353 func Sub32p(a, b int32) int32 { 354 r, ok := Sub32(a, b) 355 if !ok { 356 panic("subtraction overflow") 357 } 358 return r 359 } 360 361 // Mul32 performs * operation on two int32 operands 362 // returning a result and status 363 func Mul32(a, b int32) (int32, bool) { 364 if a == 0 || b == 0 { 365 return 0, true 366 } 367 c := a * b 368 if (c < 0) == ((a < 0) != (b < 0)) { 369 if c/b == a { 370 return c, true 371 } 372 } 373 return c, false 374 } 375 376 // Mul32p is the unchecked panicking version of Mul32 377 func Mul32p(a, b int32) int32 { 378 r, ok := Mul32(a, b) 379 if !ok { 380 panic("multiplication overflow") 381 } 382 return r 383 } 384 385 // Div32 performs / operation on two int32 operands 386 // returning a result and status 387 func Div32(a, b int32) (int32, bool) { 388 q, _, ok := Quo32(a, b) 389 return q, ok 390 } 391 392 // Div32p is the unchecked panicking version of Div32 393 func Div32p(a, b int32) int32 { 394 r, ok := Div32(a, b) 395 if !ok { 396 panic("division failure") 397 } 398 return r 399 } 400 401 // Quo32 performs + operation on two int32 operands 402 // returning a quotient, a remainder and status 403 func Quo32(a, b int32) (int32, int32, bool) { 404 if b == 0 { 405 return 0, 0, false 406 } else if b == -1 && a == math.MinInt32 { 407 return 0, 0, false 408 } 409 c := a / b 410 return c, a % b, true 411 } 412 413 // Add64 performs + operation on two int64 operands 414 // returning a result and status 415 func Add64(a, b int64) (int64, bool) { 416 c := a + b 417 if (c > a) == (b > 0) { 418 return c, true 419 } 420 return c, false 421 } 422 423 // Add64p is the unchecked panicking version of Add64 424 func Add64p(a, b int64) int64 { 425 r, ok := Add64(a, b) 426 if !ok { 427 panic("addition overflow") 428 } 429 return r 430 } 431 432 // Sub64 performs - operation on two int64 operands 433 // returning a result and status 434 func Sub64(a, b int64) (int64, bool) { 435 c := a - b 436 if (c < a) == (b > 0) { 437 return c, true 438 } 439 return c, false 440 } 441 442 // Sub64p is the unchecked panicking version of Sub64 443 func Sub64p(a, b int64) int64 { 444 r, ok := Sub64(a, b) 445 if !ok { 446 panic("subtraction overflow") 447 } 448 return r 449 } 450 451 // Mul64 performs * operation on two int64 operands 452 // returning a result and status 453 func Mul64(a, b int64) (int64, bool) { 454 if a == 0 || b == 0 { 455 return 0, true 456 } 457 c := a * b 458 if (c < 0) == ((a < 0) != (b < 0)) { 459 if c/b == a { 460 return c, true 461 } 462 } 463 return c, false 464 } 465 466 // Mul64p is the unchecked panicking version of Mul64 467 func Mul64p(a, b int64) int64 { 468 r, ok := Mul64(a, b) 469 if !ok { 470 panic("multiplication overflow") 471 } 472 return r 473 } 474 475 // Div64 performs / operation on two int64 operands 476 // returning a result and status 477 func Div64(a, b int64) (int64, bool) { 478 q, _, ok := Quo64(a, b) 479 return q, ok 480 } 481 482 // Div64p is the unchecked panicking version of Div64 483 func Div64p(a, b int64) int64 { 484 r, ok := Div64(a, b) 485 if !ok { 486 panic("division failure") 487 } 488 return r 489 } 490 491 // Quo64 performs + operation on two int64 operands 492 // returning a quotient, a remainder and status 493 func Quo64(a, b int64) (int64, int64, bool) { 494 if b == 0 { 495 return 0, 0, false 496 } else if b == -1 && a == math.MinInt64 { 497 return 0, 0, false 498 } 499 c := a / b 500 return c, a % b, true 501 }