| 1 | module math |
| 2 | |
| 3 | const pow10tab = [f64(1e+00), 1e+01, 1e+02, 1e+03, 1e+04, 1e+05, 1e+06, 1e+07, 1e+08, 1e+09, 1e+10, |
| 4 | 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, 1e+21, 1e+22, 1e+23, |
| 5 | 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31] |
| 6 | const pow10postab32 = [f64(1e+00), 1e+32, 1e+64, 1e+96, 1e+128, 1e+160, 1e+192, 1e+224, 1e+256, |
| 7 | 1e+288] |
| 8 | const pow10negtab32 = [f64(1e-00), 1e-32, 1e-64, 1e-96, 1e-128, 1e-160, 1e-192, 1e-224, 1e-256, |
| 9 | 1e-288, 1e-320] |
| 10 | |
| 11 | // powf returns base raised to the provided power. (float32) |
| 12 | @[inline] |
| 13 | pub fn powf(a f32, b f32) f32 { |
| 14 | return f32(pow(a, b)) |
| 15 | } |
| 16 | |
| 17 | // pow10 returns 10**n, the base-10 exponential of n. |
| 18 | // |
| 19 | // special cases are: |
| 20 | // pow10(n) = 0 for n < -323 |
| 21 | // pow10(n) = +inf for n > 308 |
| 22 | pub fn pow10(n int) f64 { |
| 23 | if 0 <= n && n <= 308 { |
| 24 | return pow10postab32[u32(n) / 32] * pow10tab[u32(n) % 32] |
| 25 | } |
| 26 | if -323 <= n && n <= 0 { |
| 27 | return pow10negtab32[u32(-n) / 32] / pow10tab[u32(-n) % 32] |
| 28 | } |
| 29 | // n < -323 || 308 < n |
| 30 | if n > 0 { |
| 31 | return inf(1) |
| 32 | } |
| 33 | // n < -323 |
| 34 | return 0.0 |
| 35 | } |
| 36 | |
| 37 | // powi returns base raised to power (a**b) as an integer (i64) |
| 38 | // |
| 39 | // special case: |
| 40 | // powi(a, b) = -1 for a = 0 and b < 0 |
| 41 | @[ignore_overflow] |
| 42 | pub fn powi(a i64, b i64) i64 { |
| 43 | mut b_ := b |
| 44 | mut p := a |
| 45 | mut v := i64(1) |
| 46 | |
| 47 | if b_ < 0 { // exponent < 0 |
| 48 | if a == 0 { |
| 49 | return -1 // division by 0 |
| 50 | } |
| 51 | return if a * a != 1 { |
| 52 | 0 |
| 53 | } else { |
| 54 | if (b_ & 1) > 0 { |
| 55 | a |
| 56 | } else { |
| 57 | 1 |
| 58 | } |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | for ; b_ > 0; { |
| 63 | if b_ & 1 > 0 { |
| 64 | v *= p |
| 65 | } |
| 66 | p *= p |
| 67 | b_ >>= 1 |
| 68 | } |
| 69 | |
| 70 | return v |
| 71 | } |
| 72 | |
| 73 | fn is_odd_int(x f64) bool { |
| 74 | xi, xf := modf(x) |
| 75 | return xf == 0 && (i64(xi) & 1) == 1 |
| 76 | } |
| 77 | |
| 78 | // pow returns the base x, raised to the provided power y. (float64) |
| 79 | // |
| 80 | // todo(playXE): make this function work on JS backend, probably problem of JS codegen that it does not work. |
| 81 | pub fn pow(x f64, y f64) f64 { |
| 82 | if y == 0 || x == 1 { |
| 83 | return 1 |
| 84 | } else if y == 1 { |
| 85 | return x |
| 86 | } else if is_nan(x) || is_nan(y) { |
| 87 | return nan() |
| 88 | } else if y == 2 { |
| 89 | return x * x |
| 90 | } else if y == 3 { |
| 91 | return x * x * x |
| 92 | } else if x == 0 { |
| 93 | if y < 0 { |
| 94 | if is_odd_int(y) { |
| 95 | return copysign(inf(1), x) |
| 96 | } |
| 97 | return inf(1) |
| 98 | } else if y > 0 { |
| 99 | if is_odd_int(y) { |
| 100 | return x |
| 101 | } |
| 102 | return 0 |
| 103 | } |
| 104 | } else if is_inf(y, 0) { |
| 105 | if x == -1 { |
| 106 | return 1 |
| 107 | } else if (abs(x) < 1) == is_inf(y, 1) { |
| 108 | return 0 |
| 109 | } else { |
| 110 | return inf(1) |
| 111 | } |
| 112 | } else if is_inf(x, 0) { |
| 113 | if is_inf(x, -1) { |
| 114 | return pow(1 / x, -y) |
| 115 | } |
| 116 | |
| 117 | if y < 0 { |
| 118 | return 0 |
| 119 | } else if y > 0 { |
| 120 | return inf(1) |
| 121 | } |
| 122 | } else if y == 0.5 { |
| 123 | return sqrt(x) |
| 124 | } else if y == -0.5 { |
| 125 | return 1 / sqrt(x) |
| 126 | } |
| 127 | mut yi, mut yf := modf(abs(y)) |
| 128 | |
| 129 | if yf != 0 && x < 0 { |
| 130 | return nan() |
| 131 | } |
| 132 | if yi >= (u64(1) << 63) { |
| 133 | // yi is a large even int that will lead to overflow (or underflow to 0) |
| 134 | // for all x except -1 (x == 1 was handled earlier) |
| 135 | |
| 136 | if x == -1 { |
| 137 | return 1 |
| 138 | } else if (abs(x) < 1) == (y > 0) { |
| 139 | return 0 |
| 140 | } else { |
| 141 | return inf(1) |
| 142 | } |
| 143 | } |
| 144 | |
| 145 | if yf == 0.0 { |
| 146 | mut result := x |
| 147 | for _ in 1 .. i64(yi) { |
| 148 | result *= x |
| 149 | } |
| 150 | if y > 0 { |
| 151 | return result |
| 152 | } |
| 153 | return 1 / result |
| 154 | } |
| 155 | |
| 156 | // ans = a1 * 2**ae (= 1 for now). |
| 157 | mut a1 := 1.0 |
| 158 | mut ae := 0 |
| 159 | |
| 160 | // ans *= x**yf |
| 161 | if yf != 0 { |
| 162 | if yf > 0.5 { |
| 163 | yf-- |
| 164 | yi++ |
| 165 | } |
| 166 | |
| 167 | a1 = exp(yf * log(x)) |
| 168 | } |
| 169 | |
| 170 | // ans *= x**yi |
| 171 | // by multiplying in successive squarings |
| 172 | // of x according to bits of yi. |
| 173 | // accumulate powers of two into exp. |
| 174 | mut x1, mut xe := frexp(x) |
| 175 | |
| 176 | for i := i64(yi); i != 0; i >>= 1 { |
| 177 | // these series of casts is a little weird but we have to do them to prevent left shift of negative error |
| 178 | if xe < int(u32(u32(-1) << 12)) || 1 << 12 < xe { |
| 179 | // catch xe before it overflows the left shift below |
| 180 | // Since i !=0 it has at least one bit still set, so ae will accumulate xe |
| 181 | // on at least one more iteration, ae += xe is a lower bound on ae |
| 182 | // the lower bound on ae exceeds the size of a float64 exp |
| 183 | // so the final call to Ldexp will produce under/overflow (0/Inf) |
| 184 | ae += xe |
| 185 | break |
| 186 | } |
| 187 | if i & 1 == 1 { |
| 188 | a1 *= x1 |
| 189 | ae += xe |
| 190 | } |
| 191 | x1 *= x1 |
| 192 | xe <<= 1 |
| 193 | if x1 < .5 { |
| 194 | x1 += x1 |
| 195 | xe-- |
| 196 | } |
| 197 | } |
| 198 | |
| 199 | // ans = a1*2**ae |
| 200 | // if y < 0 { ans = 1 / ans } |
| 201 | // but in the opposite order |
| 202 | if y < 0 { |
| 203 | a1 = 1 / a1 |
| 204 | ae = -ae |
| 205 | } |
| 206 | return ldexp(a1, ae) |
| 207 | } |
| 208 | |