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  }