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 }