github.com/seeker-insurance/kit@v0.0.13/imath/imath.go (about)

     1  //Package imath contains tools for signed integer math. It largely corresponds with go's built in `math` library for float64s
     2  package imath
     3  
     4  import "math/rand"
     5  import "github.com/seeker-insurance/kit/imath/operator"
     6  
     7  const (
     8  	is64bit = uint64(^uint(0)) == ^uint64(0)
     9  )
    10  
    11  //Sum returns the sum of it's arguments. Sum() is 0
    12  func Sum(a ...int) int {
    13  	return Reduce(operator.Add, 0, a...)
    14  }
    15  
    16  //Range returns the slice of integers in [start, stop) obtained by repeatedly adding step to start.
    17  func Range(start, stop, step int) []int {
    18  	if (start > stop && step > 0) ||
    19  		(start < stop && step < 0) || step == 0 {
    20  		return nil
    21  	}
    22  	a := make([]int, 0, Abs(start-stop)/Abs(step))
    23  	if step < 0 {
    24  		for n := start; n > stop; n += step {
    25  			a = append(a, n)
    26  		}
    27  		return a
    28  	}
    29  
    30  	for n := start; n < stop; n += step {
    31  		a = append(a, n)
    32  	}
    33  
    34  	return a
    35  }
    36  
    37  //Product returns the product of it's arguments. Product() is 1.
    38  func Product(a ...int) int {
    39  	return Reduce(operator.Mul, 1, a...)
    40  }
    41  
    42  //Max returns it's largest integer argument.
    43  func Max(n int, a ...int) int {
    44  	return Reduce(Max2, n, a...)
    45  }
    46  
    47  //Max2 returns the largest of two integer arguments.
    48  func Max2(a, b int) int {
    49  	if a > b {
    50  		return a
    51  	}
    52  	return b
    53  }
    54  
    55  //Min returns it's smallest integer argument.
    56  func Min(n int, a ...int) int {
    57  	return Reduce(Min2, n, a...)
    58  }
    59  
    60  //Min2 returns the smallest of two integer arguments.
    61  func Min2(a, b int) int {
    62  	if a < b {
    63  		return a
    64  	}
    65  	return b
    66  }
    67  
    68  //Abs returns the absolute value of n
    69  func Abs(n int) int {
    70  	if n >= 0 {
    71  		return n
    72  	}
    73  	return -n
    74  }
    75  
    76  //RandSign returns -1 or 1 at random, using the default Source of math/rand. This is NOT crypto-safe, at all.
    77  func RandSign() int {
    78  	if rand.Intn(2) > 0 {
    79  		return 1
    80  	}
    81  	return -1
    82  }
    83  
    84  //Clamp takes an int n, returns low if n < low, high if n > high, and n otherwise.
    85  func Clamp(n, low, high int) int {
    86  	if n < low {
    87  		return low
    88  	} else if n > high {
    89  		return high
    90  	}
    91  	return n
    92  }
    93  
    94  //Sign returns the sign of the operand. The sign of zero is zero.
    95  func Sign(n int) int {
    96  	switch {
    97  	case n < 0:
    98  		return -1
    99  
   100  	case n == 0:
   101  		return 0
   102  
   103  	default:
   104  		return 1
   105  	}
   106  }
   107  
   108  //Pow is an efficent implementation of exponentiation by squaring.
   109  func Pow(base, exp int) int {
   110  	result := 1
   111  	for ; exp > 0; exp >>= 1 {
   112  		if exp&1 > 0 {
   113  			result *= base
   114  		}
   115  		base *= base
   116  	}
   117  	return result
   118  }
   119  
   120  func naivePow(base, exp int) int {
   121  	result := 1
   122  	for ; exp > 0; exp-- {
   123  		result *= base
   124  	}
   125  	return result
   126  }
   127  
   128  //TODO - test is broken
   129  /*
   130  func PowMod(base, exp, mod int) int {
   131  	base %= mod
   132  	exp %= mod
   133  
   134  	result := 1
   135  	for ; exp > 0; exp >>= 1 {
   136  		if exp&1 > 0 {
   137  			result = result * base % mod
   138  		}
   139  		base = base * base % mod
   140  
   141  	}
   142  	return result
   143  }
   144  
   145  
   146  func PowModSafe(base, exp, mod int) (int, bool) {
   147  	base %= mod
   148  	if exp < 0 {
   149  		return 0, false // negative exponent is unclear
   150  	}
   151  	exp %= mod
   152  
   153  	if is64bit && (math.MaxInt64/base) < base {
   154  		return 0, false
   155  	} else if math.MaxInt32/base < base {
   156  		return 0, false
   157  	}
   158  	// cannot exponentiate base because it will overflow int
   159  	result := 1
   160  	for ; exp > 0; exp >>= 1 {
   161  		if exp&1 > 0 {
   162  			result = result * base % mod
   163  		}
   164  		base = base * base % mod
   165  	}
   166  	return result, true
   167  }
   168  */