github.com/mitranim/gg@v0.1.17/math.go (about)

     1  package gg
     2  
     3  import (
     4  	"math"
     5  )
     6  
     7  /*
     8  Short for "is finite". Missing feature of the standard "math" package.
     9  True if the input is neither NaN nor infinity.
    10  */
    11  func IsFin[A Float](val A) bool {
    12  	tar := float64(val)
    13  	return !math.IsNaN(tar) && !math.IsInf(tar, 0)
    14  }
    15  
    16  // Short for "is natural". True if >= 0. Also see `IsPos`.
    17  func IsNat[A Num](val A) bool { return val >= 0 }
    18  
    19  // Short for "is positive". True if > 0. Also see `IsNat`.
    20  func IsPos[A Num](val A) bool { return val > 0 }
    21  
    22  // Short for "is negative". True if < 0. Also see `IsNat`.
    23  func IsNeg[A Num](val A) bool { return val < 0 }
    24  
    25  /*
    26  True if the remainder of dividing the first argument by the second argument is
    27  zero. If the divisor is zero, does not attempt the division and returns false.
    28  Note that the result is unaffected by the signs of either the dividend or the
    29  divisor.
    30  */
    31  func IsDivisibleBy[A Int](dividend, divisor A) bool {
    32  	return divisor != 0 && dividend%divisor == 0
    33  }
    34  
    35  // Same as `Add(val, 1)`. Panics on overflow.
    36  func Inc[A Int](val A) A { return Add(val, 1) }
    37  
    38  // Same as `Sub(val, 1)`. Panics on underflow.
    39  func Dec[A Int](val A) A { return Sub(val, 1) }
    40  
    41  /*
    42  Raises a number to a power. Same as `math.Pow` and calls it under the hood, but
    43  accepts arbitrary numeric types and performs checked conversions via `NumConv`.
    44  Panics on overflow or precision loss. Has minor overhead over `math.Pow`.
    45  Compare `PowUncheck` which runs faster but may overflow.
    46  */
    47  func Pow[Tar, Pow Num](src Tar, pow Pow) Tar {
    48  	return NumConv[Tar](math.Pow(NumConv[float64](src), NumConv[float64](pow)))
    49  }
    50  
    51  /*
    52  Raises a number to a power. Same as `math.Pow` and calls it under the hood, but
    53  accepts arbitrary numeric types. Does not check for overflow or precision loss.
    54  Counterpart to `Pow` which panics on overflow.
    55  */
    56  func PowUncheck[Tar, Pow Num](src Tar, pow Pow) Tar {
    57  	return Tar(math.Pow(float64(src), float64(pow)))
    58  }
    59  
    60  /*
    61  Checked factorial. Panics on overflow. Compare `FacUncheck` which runs faster,
    62  but may overflow.
    63  */
    64  func Fac[A Uint](src A) A {
    65  	var tar float64 = 1
    66  	mul := NumConv[float64](src)
    67  	for mul > 0 {
    68  		tar *= mul
    69  		mul--
    70  	}
    71  	return NumConv[A](tar)
    72  }
    73  
    74  /*
    75  Unchecked factorial. May overflow. Counterpart to `Fac` which panics on
    76  overflow.
    77  */
    78  func FacUncheck[A Uint](src A) A {
    79  	var out A = 1
    80  	for src > 0 {
    81  		out *= src
    82  		src -= 1
    83  	}
    84  	return out
    85  }
    86  
    87  // Checked addition. Panics on overflow/underflow. Has overhead.
    88  func Add[A Int](one, two A) A {
    89  	out := one + two
    90  	if (out > one) == (two > 0) {
    91  		return out
    92  	}
    93  	panic(errAdd(one, two, out))
    94  }
    95  
    96  func errAdd[A Int](one, two, out A) Err {
    97  	return Errf(
    98  		`addition overflow for %v: %v + %v = %v`,
    99  		Type[A](), one, two, out,
   100  	)
   101  }
   102  
   103  /*
   104  Unchecked addition. Same as Go's `+` operator for numbers, expressed as a
   105  generic function. Does not take strings. May overflow. For integers, prefer
   106  `Add` whenever possible, which has overflow checks.
   107  */
   108  func AddUncheck[A Num](one, two A) A { return one + two }
   109  
   110  // Checked subtraction. Panics on overflow/underflow. Has overhead.
   111  func Sub[A Int](one, two A) A {
   112  	out := one - two
   113  	if (out < one) == (two > 0) {
   114  		return out
   115  	}
   116  	panic(errSub(one, two, out))
   117  }
   118  
   119  func errSub[A Int](one, two, out A) Err {
   120  	return Errf(
   121  		`subtraction overflow for %v: %v - %v = %v`,
   122  		Type[A](), one, two, out,
   123  	)
   124  }
   125  
   126  /*
   127  Unchecked subtraction. Same as Go's `-` operator, expressed as a generic
   128  function. May overflow. For integers, prefer `Sub` whenever possible, which has
   129  overflow checks.
   130  */
   131  func SubUncheck[A Num](one, two A) A { return one - two }
   132  
   133  // Checked multiplication. Panics on overflow/underflow. Has overhead.
   134  func Mul[A Int](one, two A) A {
   135  	if one == 0 || two == 0 {
   136  		return 0
   137  	}
   138  	out := one * two
   139  	if ((one < 0) == (two < 0)) != (out < 0) && out/two == one {
   140  		return out
   141  	}
   142  	panic(errMul(one, two, out))
   143  }
   144  
   145  func errMul[A Int](one, two, out A) Err {
   146  	return Errf(
   147  		`multiplication overflow for %v: %v * %v = %v`,
   148  		Type[A](), one, two, out,
   149  	)
   150  }
   151  
   152  /*
   153  Checked numeric conversion. Same as `Out(src)` but with additional assertions.
   154  Panics in case of overflow, underflow, imprecision such as converting large
   155  integers to floats that don't support integers in that range, or anything
   156  involving NaN. Performance overhead is minimal.
   157  */
   158  func NumConv[Out, Src Num](src Src) Out {
   159  	out := Out(src)
   160  	if !(src == Src(out)) ||
   161  		(src < 0 && out >= 0) ||
   162  		(src >= 0 && out < 0) {
   163  		panic(errNumConv(src, out))
   164  	}
   165  	return out
   166  }
   167  
   168  // Uses `String` to avoid the scientific notation for floats.
   169  func errNumConv[Out, Src Num](src Src, out Out) Err {
   170  	return Errf(
   171  		`unable to safely convert %v %v to %v %v due to overflow, underflow, or imprecision`,
   172  		Type[Src](), String(src), Type[Out](), String(out),
   173  	)
   174  }