@typeonce/ritmo-math 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +183 -0
- package/README.md +14 -4
- package/dist/Collide2.d.ts +2 -1
- package/dist/Collide2.d.ts.map +1 -1
- package/dist/Collide2.js +10 -6
- package/dist/Collide2.js.map +1 -1
- package/dist/FlowField.d.ts.map +1 -1
- package/dist/FlowField.js +2 -1
- package/dist/FlowField.js.map +1 -1
- package/dist/InputAxis.js +1 -1
- package/dist/Ops.d.ts +209 -0
- package/dist/Ops.d.ts.map +1 -0
- package/dist/Ops.js +210 -0
- package/dist/Ops.js.map +1 -0
- package/dist/Random.d.ts +63 -10
- package/dist/Random.d.ts.map +1 -1
- package/dist/Random.js +57 -32
- package/dist/Random.js.map +1 -1
- package/dist/Scalar.d.ts +7 -2
- package/dist/Scalar.d.ts.map +1 -1
- package/dist/Scalar.js +2 -1
- package/dist/Scalar.js.map +1 -1
- package/dist/SpatialGrid.d.ts +7 -2
- package/dist/SpatialGrid.d.ts.map +1 -1
- package/dist/SpatialGrid.js +35 -4
- package/dist/SpatialGrid.js.map +1 -1
- package/dist/Vec2.d.ts.map +1 -1
- package/dist/Vec2.js +8 -7
- package/dist/Vec2.js.map +1 -1
- package/dist/Vector2.d.ts +12 -0
- package/dist/Vector2.d.ts.map +1 -1
- package/dist/Vector2.js +12 -0
- package/dist/Vector2.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/fdlibm.d.ts +43 -0
- package/dist/internal/fdlibm.d.ts.map +1 -0
- package/dist/internal/fdlibm.js +1291 -0
- package/dist/internal/fdlibm.js.map +1 -0
- package/dist/internal/vector2.d.ts.map +1 -1
- package/dist/internal/vector2.js +2 -1
- package/dist/internal/vector2.js.map +1 -1
- package/package.json +3 -2
- package/src/Collide2.ts +10 -6
- package/src/FlowField.ts +2 -1
- package/src/InputAxis.ts +1 -1
- package/src/Ops.ts +232 -0
- package/src/Random.ts +104 -16
- package/src/Scalar.ts +7 -2
- package/src/SpatialGrid.ts +40 -6
- package/src/Vec2.ts +9 -7
- package/src/Vector2.ts +12 -0
- package/src/index.ts +5 -0
- package/src/internal/fdlibm.ts +1256 -0
- package/src/internal/vector2.ts +2 -1
|
@@ -0,0 +1,1256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure-JavaScript ports of FreeBSD msun / musl libm (originally Sun fdlibm),
|
|
3
|
+
* built only from `+ - * /`, `Math.sqrt`, and bit access. ECMAScript rounds
|
|
4
|
+
* each of those exactly, so every engine and CPU returns the same bits.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (C) 1993-2004 by Sun Microsystems, Inc. All rights reserved.
|
|
7
|
+
* Developed at SunSoft, a Sun Microsystems, Inc. business.
|
|
8
|
+
* Permission to use, copy, modify, and distribute this software is freely
|
|
9
|
+
* granted, provided that this notice is preserved.
|
|
10
|
+
*
|
|
11
|
+
* musl libm is MIT licensed, Copyright (c) 2005-2020 Rich Felker, et al.
|
|
12
|
+
*
|
|
13
|
+
* Changes from the C sources: results follow ECMAScript where it differs from
|
|
14
|
+
* C (`pow(1, NaN)` and `pow(±1, ±Infinity)` are NaN), arguments of sin,
|
|
15
|
+
* cos, and tan beyond 2^20·π/2 are reduced exactly with BigInt instead of
|
|
16
|
+
* `__rem_pio2_large`, and `exp(1)` returns `Math.E`.
|
|
17
|
+
*
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
const scratch = new Float64Array(1)
|
|
22
|
+
const words = new Uint32Array(scratch.buffer)
|
|
23
|
+
const LITTLE_ENDIAN = new Uint8Array(new Uint16Array([1]).buffer)[0] === 1
|
|
24
|
+
const HI = LITTLE_ENDIAN ? 1 : 0
|
|
25
|
+
const LO = LITTLE_ENDIAN ? 0 : 1
|
|
26
|
+
|
|
27
|
+
/** The high 32 bits of `x`, as a signed integer (sign, exponent, top of the mantissa). */
|
|
28
|
+
const highWord = (x: number): number => {
|
|
29
|
+
scratch[0] = x
|
|
30
|
+
return words[HI]! | 0
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** The low 32 bits of `x`, unsigned. */
|
|
34
|
+
const lowWord = (x: number): number => {
|
|
35
|
+
scratch[0] = x
|
|
36
|
+
return words[LO]!
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const fromWords = (high: number, low: number): number => {
|
|
40
|
+
words[HI] = high
|
|
41
|
+
words[LO] = low
|
|
42
|
+
return scratch[0]!
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** `x` with its low 32 bits cleared. */
|
|
46
|
+
const clearLow = (x: number): number => {
|
|
47
|
+
scratch[0] = x
|
|
48
|
+
words[LO] = 0
|
|
49
|
+
return scratch[0]!
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const TWO_1023 = fromWords(0x7fe00000, 0)
|
|
53
|
+
const TWO_M1022 = fromWords(0x00100000, 0)
|
|
54
|
+
const TWO_53 = 9007199254740992
|
|
55
|
+
|
|
56
|
+
/** `x * 2^n`, rounded once. */
|
|
57
|
+
const scalbn = (x: number, n: number): number => {
|
|
58
|
+
let y = x
|
|
59
|
+
let k = n
|
|
60
|
+
if (k > 1023) {
|
|
61
|
+
y *= TWO_1023
|
|
62
|
+
k -= 1023
|
|
63
|
+
if (k > 1023) {
|
|
64
|
+
y *= TWO_1023
|
|
65
|
+
k -= 1023
|
|
66
|
+
if (k > 1023) k = 1023
|
|
67
|
+
}
|
|
68
|
+
} else if (k < -1022) {
|
|
69
|
+
// Keep the final k below -53 to avoid double rounding into subnormals.
|
|
70
|
+
y *= TWO_M1022 * TWO_53
|
|
71
|
+
k += 1022 - 53
|
|
72
|
+
if (k < -1022) {
|
|
73
|
+
y *= TWO_M1022 * TWO_53
|
|
74
|
+
k += 1022 - 53
|
|
75
|
+
if (k < -1022) k = -1022
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return y * fromWords((0x3ff + k) << 20, 0)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
// Argument reduction: x = n·(π/2) + (y0 + y1), |y0 + y1| <= π/4
|
|
83
|
+
|
|
84
|
+
let reducedHigh = 0
|
|
85
|
+
let reducedLow = 0
|
|
86
|
+
|
|
87
|
+
const TO_INT = 1.5 / 2.220446049250313e-16
|
|
88
|
+
const PIO4 = 7.85398163397448278999e-01
|
|
89
|
+
const INVPIO2 = 6.36619772367581382433e-01
|
|
90
|
+
const PIO2_1 = 1.57079632673412561417e+00
|
|
91
|
+
const PIO2_1T = 6.07710050650619224932e-11
|
|
92
|
+
const PIO2_2 = 6.07710050630396597660e-11
|
|
93
|
+
const PIO2_2T = 2.02226624879595063154e-21
|
|
94
|
+
const PIO2_3 = 2.02226624871116645580e-21
|
|
95
|
+
const PIO2_3T = 8.47842766036889956997e-32
|
|
96
|
+
|
|
97
|
+
/** Sets `reducedHigh`/`reducedLow` and returns n (only n mod 4 is meaningful for huge x). */
|
|
98
|
+
const remPio2 = (x: number): number => {
|
|
99
|
+
const ix = highWord(x) & 0x7fffffff
|
|
100
|
+
if (ix < 0x413921fb) {
|
|
101
|
+
// |x| < 2^20·π/2: Cody–Waite reduction with up to three rounds.
|
|
102
|
+
let fn = x * INVPIO2 + TO_INT - TO_INT
|
|
103
|
+
let n = fn | 0
|
|
104
|
+
let r = x - fn * PIO2_1
|
|
105
|
+
let w = fn * PIO2_1T
|
|
106
|
+
if (r - w < -PIO4) {
|
|
107
|
+
n--
|
|
108
|
+
fn--
|
|
109
|
+
r = x - fn * PIO2_1
|
|
110
|
+
w = fn * PIO2_1T
|
|
111
|
+
} else if (r - w > PIO4) {
|
|
112
|
+
n++
|
|
113
|
+
fn++
|
|
114
|
+
r = x - fn * PIO2_1
|
|
115
|
+
w = fn * PIO2_1T
|
|
116
|
+
}
|
|
117
|
+
let y0 = r - w
|
|
118
|
+
const ex = ix >> 20
|
|
119
|
+
let ey = (highWord(y0) >> 20) & 0x7ff
|
|
120
|
+
if (ex - ey > 16) {
|
|
121
|
+
let t = r
|
|
122
|
+
w = fn * PIO2_2
|
|
123
|
+
r = t - w
|
|
124
|
+
w = fn * PIO2_2T - ((t - r) - w)
|
|
125
|
+
y0 = r - w
|
|
126
|
+
ey = (highWord(y0) >> 20) & 0x7ff
|
|
127
|
+
if (ex - ey > 49) {
|
|
128
|
+
t = r
|
|
129
|
+
w = fn * PIO2_3
|
|
130
|
+
r = t - w
|
|
131
|
+
w = fn * PIO2_3T - ((t - r) - w)
|
|
132
|
+
y0 = r - w
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
reducedHigh = y0
|
|
136
|
+
reducedLow = (r - y0) - w
|
|
137
|
+
return n
|
|
138
|
+
}
|
|
139
|
+
if (ix >= 0x7ff00000) {
|
|
140
|
+
reducedHigh = x - x
|
|
141
|
+
reducedLow = reducedHigh
|
|
142
|
+
return 0
|
|
143
|
+
}
|
|
144
|
+
return remPio2Large(x)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Huge arguments: exact reduction with BigInt against 2/π to 1280 bits.
|
|
148
|
+
|
|
149
|
+
const PI_BITS = 1400
|
|
150
|
+
let twoOverPi = 0n
|
|
151
|
+
let halfPi130 = 0n
|
|
152
|
+
|
|
153
|
+
/** arctan(1/k) · 2^bits, by its Taylor series in fixed point. */
|
|
154
|
+
const arctanInverse = (k: bigint, bits: bigint): bigint => {
|
|
155
|
+
const one = 1n << bits
|
|
156
|
+
const k2 = k * k
|
|
157
|
+
let power = one / k
|
|
158
|
+
let sum = power
|
|
159
|
+
for (let i = 1n; power !== 0n; i++) {
|
|
160
|
+
power /= k2
|
|
161
|
+
const term = power / (2n * i + 1n)
|
|
162
|
+
sum = i % 2n === 1n ? sum - term : sum + term
|
|
163
|
+
}
|
|
164
|
+
return sum
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const TWO_OVER_PI_BITS = 1280n
|
|
168
|
+
|
|
169
|
+
const initReduction = (): void => {
|
|
170
|
+
const bits = BigInt(PI_BITS)
|
|
171
|
+
// Machin: π = 16·atan(1/5) − 4·atan(1/239)
|
|
172
|
+
const pi = 16n * arctanInverse(5n, bits) - 4n * arctanInverse(239n, bits)
|
|
173
|
+
twoOverPi = (1n << (TWO_OVER_PI_BITS + 1n + bits)) / pi
|
|
174
|
+
halfPi130 = pi >> (bits - 129n)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const remPio2Large = (x: number): number => {
|
|
178
|
+
if (twoOverPi === 0n) initReduction()
|
|
179
|
+
const negative = x < 0
|
|
180
|
+
const ax = negative ? -x : x
|
|
181
|
+
// ax = mantissa · 2^exponent, exactly (ax >= 2^20 here, so it is normal).
|
|
182
|
+
const exponent = ((highWord(ax) >> 20) & 0x7ff) - 1075
|
|
183
|
+
const mantissa = BigInt(ax / fromWords((exponent + 1023) << 20, 0))
|
|
184
|
+
// ax · 2/π = product / 2^shift
|
|
185
|
+
const shift = TWO_OVER_PI_BITS - BigInt(exponent)
|
|
186
|
+
const product = mantissa * twoOverPi
|
|
187
|
+
const unit = 1n << shift
|
|
188
|
+
let n = Number((product >> shift) & 3n)
|
|
189
|
+
let fraction = product & (unit - 1n)
|
|
190
|
+
if (fraction >= unit >> 1n) {
|
|
191
|
+
fraction -= unit
|
|
192
|
+
n = (n + 1) & 3
|
|
193
|
+
}
|
|
194
|
+
// Keep 250 fraction bits, multiply by π/2 (130 bits): r = fraction·π/2 · 2^-380
|
|
195
|
+
const r = (fraction >> (shift - 250n)) * halfPi130
|
|
196
|
+
const scale = fromWords((380 + 1023) << 20, 0)
|
|
197
|
+
const high = Number(r) / scale
|
|
198
|
+
const low = Number(r - BigInt(high * scale)) / scale
|
|
199
|
+
reducedHigh = negative ? -high : high
|
|
200
|
+
reducedLow = negative ? -low : low
|
|
201
|
+
return negative ? -n : n
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// ---------------------------------------------------------------------------
|
|
205
|
+
// Kernels on [-π/4, π/4]
|
|
206
|
+
|
|
207
|
+
const S1 = -1.66666666666666324348e-01
|
|
208
|
+
const S2 = 8.33333333332248946124e-03
|
|
209
|
+
const S3 = -1.98412698298579493134e-04
|
|
210
|
+
const S4 = 2.75573137070700676789e-06
|
|
211
|
+
const S5 = -2.50507602534068634195e-08
|
|
212
|
+
const S6 = 1.58969099521155010221e-10
|
|
213
|
+
|
|
214
|
+
const kernelSin = (x: number, y: number, hasTail: boolean): number => {
|
|
215
|
+
const z = x * x
|
|
216
|
+
const w = z * z
|
|
217
|
+
const r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6)
|
|
218
|
+
const v = z * x
|
|
219
|
+
if (!hasTail) return x + v * (S1 + z * r)
|
|
220
|
+
return x - ((z * (0.5 * y - v * r) - y) - v * S1)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const C1 = 4.16666666666666019037e-02
|
|
224
|
+
const C2 = -1.38888888888741095749e-03
|
|
225
|
+
const C3 = 2.48015872894767294178e-05
|
|
226
|
+
const C4 = -2.75573143513906633035e-07
|
|
227
|
+
const C5 = 2.08757232129817482790e-09
|
|
228
|
+
const C6 = -1.13596475577881948265e-11
|
|
229
|
+
|
|
230
|
+
const kernelCos = (x: number, y: number): number => {
|
|
231
|
+
const z = x * x
|
|
232
|
+
const w = z * z
|
|
233
|
+
const r = z * (C1 + z * (C2 + z * C3)) + w * w * (C4 + z * (C5 + z * C6))
|
|
234
|
+
const hz = 0.5 * z
|
|
235
|
+
const v = 1.0 - hz
|
|
236
|
+
return v + (((1.0 - v) - hz) + (z * r - x * y))
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const T = [
|
|
240
|
+
3.33333333333334091986e-01,
|
|
241
|
+
1.33333333333201242699e-01,
|
|
242
|
+
5.39682539762260521377e-02,
|
|
243
|
+
2.18694882948595424599e-02,
|
|
244
|
+
8.86323982359930005737e-03,
|
|
245
|
+
3.59207910759131235356e-03,
|
|
246
|
+
1.45620945432529025516e-03,
|
|
247
|
+
5.88041240820264096874e-04,
|
|
248
|
+
2.46463134818469906812e-04,
|
|
249
|
+
7.81794442939557092300e-05,
|
|
250
|
+
7.14072491382608190305e-05,
|
|
251
|
+
-1.85586374855275456654e-05,
|
|
252
|
+
2.59073051863633712884e-05
|
|
253
|
+
] as const
|
|
254
|
+
const PIO4_LO = 3.06161699786838301793e-17
|
|
255
|
+
|
|
256
|
+
/** tan(x + y) when `odd` is false, -1/tan(x + y) when it is true. */
|
|
257
|
+
const kernelTan = (xIn: number, yIn: number, odd: boolean): number => {
|
|
258
|
+
let x = xIn
|
|
259
|
+
let y = yIn
|
|
260
|
+
const hx = highWord(x)
|
|
261
|
+
const big = (hx & 0x7fffffff) >= 0x3fe59428 // |x| >= 0.6744
|
|
262
|
+
const negative = hx < 0
|
|
263
|
+
if (big) {
|
|
264
|
+
if (negative) {
|
|
265
|
+
x = -x
|
|
266
|
+
y = -y
|
|
267
|
+
}
|
|
268
|
+
x = (PIO4 - x) + (PIO4_LO - y)
|
|
269
|
+
y = 0.0
|
|
270
|
+
}
|
|
271
|
+
const z = x * x
|
|
272
|
+
let w = z * z
|
|
273
|
+
let r = T[1] + w * (T[3] + w * (T[5] + w * (T[7] + w * (T[9] + w * T[11]))))
|
|
274
|
+
let v = z * (T[2] + w * (T[4] + w * (T[6] + w * (T[8] + w * (T[10] + w * T[12])))))
|
|
275
|
+
let s = z * x
|
|
276
|
+
r = y + z * (s * (r + v) + y) + s * T[0]
|
|
277
|
+
w = x + r
|
|
278
|
+
if (big) {
|
|
279
|
+
s = odd ? -1 : 1
|
|
280
|
+
v = s - 2.0 * (x + (r - w * w / (w + s)))
|
|
281
|
+
return negative ? -v : v
|
|
282
|
+
}
|
|
283
|
+
if (!odd) return w
|
|
284
|
+
// -1/(x + r) has up to 2 ulp error, so compute it accurately.
|
|
285
|
+
const w0 = clearLow(w)
|
|
286
|
+
v = r - (w0 - x)
|
|
287
|
+
const a = -1.0 / w
|
|
288
|
+
const a0 = clearLow(a)
|
|
289
|
+
return a0 + a * (1.0 + a0 * w0 + a0 * v)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// ---------------------------------------------------------------------------
|
|
293
|
+
// Trigonometric functions
|
|
294
|
+
|
|
295
|
+
export const sin = (x: number): number => {
|
|
296
|
+
const ix = highWord(x) & 0x7fffffff
|
|
297
|
+
if (ix <= 0x3fe921fb) {
|
|
298
|
+
if (ix < 0x3e500000) return x // |x| < 2^-26
|
|
299
|
+
return kernelSin(x, 0, false)
|
|
300
|
+
}
|
|
301
|
+
if (ix >= 0x7ff00000) return x - x
|
|
302
|
+
const n = remPio2(x)
|
|
303
|
+
switch (n & 3) {
|
|
304
|
+
case 0:
|
|
305
|
+
return kernelSin(reducedHigh, reducedLow, true)
|
|
306
|
+
case 1:
|
|
307
|
+
return kernelCos(reducedHigh, reducedLow)
|
|
308
|
+
case 2:
|
|
309
|
+
return -kernelSin(reducedHigh, reducedLow, true)
|
|
310
|
+
default:
|
|
311
|
+
return -kernelCos(reducedHigh, reducedLow)
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export const cos = (x: number): number => {
|
|
316
|
+
const ix = highWord(x) & 0x7fffffff
|
|
317
|
+
if (ix <= 0x3fe921fb) {
|
|
318
|
+
if (ix < 0x3e46a09e) return 1.0 // |x| < 2^-27·√2
|
|
319
|
+
return kernelCos(x, 0)
|
|
320
|
+
}
|
|
321
|
+
if (ix >= 0x7ff00000) return x - x
|
|
322
|
+
const n = remPio2(x)
|
|
323
|
+
switch (n & 3) {
|
|
324
|
+
case 0:
|
|
325
|
+
return kernelCos(reducedHigh, reducedLow)
|
|
326
|
+
case 1:
|
|
327
|
+
return -kernelSin(reducedHigh, reducedLow, true)
|
|
328
|
+
case 2:
|
|
329
|
+
return -kernelCos(reducedHigh, reducedLow)
|
|
330
|
+
default:
|
|
331
|
+
return kernelSin(reducedHigh, reducedLow, true)
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
export const tan = (x: number): number => {
|
|
336
|
+
const ix = highWord(x) & 0x7fffffff
|
|
337
|
+
if (ix <= 0x3fe921fb) {
|
|
338
|
+
if (ix < 0x3e400000) return x // |x| < 2^-27
|
|
339
|
+
return kernelTan(x, 0.0, false)
|
|
340
|
+
}
|
|
341
|
+
if (ix >= 0x7ff00000) return x - x
|
|
342
|
+
const n = remPio2(x)
|
|
343
|
+
return kernelTan(reducedHigh, reducedLow, (n & 1) !== 0)
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// ---------------------------------------------------------------------------
|
|
347
|
+
// Inverse trigonometric functions
|
|
348
|
+
|
|
349
|
+
const PIO2_HI = 1.57079632679489655800e+00
|
|
350
|
+
const PIO2_LO = 6.12323399573676603587e-17
|
|
351
|
+
const PS0 = 1.66666666666666657415e-01
|
|
352
|
+
const PS1 = -3.25565818622400915405e-01
|
|
353
|
+
const PS2 = 2.01212532134862925881e-01
|
|
354
|
+
const PS3 = -4.00555345006794114027e-02
|
|
355
|
+
const PS4 = 7.91534994289814532176e-04
|
|
356
|
+
const PS5 = 3.47933107596021167570e-05
|
|
357
|
+
const QS1 = -2.40339491173441421878e+00
|
|
358
|
+
const QS2 = 2.02094576023350569471e+00
|
|
359
|
+
const QS3 = -6.88283971605453293030e-01
|
|
360
|
+
const QS4 = 7.70381505559019352791e-02
|
|
361
|
+
|
|
362
|
+
const asinRatio = (z: number): number => {
|
|
363
|
+
const p = z * (PS0 + z * (PS1 + z * (PS2 + z * (PS3 + z * (PS4 + z * PS5)))))
|
|
364
|
+
const q = 1.0 + z * (QS1 + z * (QS2 + z * (QS3 + z * QS4)))
|
|
365
|
+
return p / q
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export const asin = (x: number): number => {
|
|
369
|
+
const hx = highWord(x)
|
|
370
|
+
const ix = hx & 0x7fffffff
|
|
371
|
+
if (ix >= 0x3ff00000) {
|
|
372
|
+
// |x| >= 1 or NaN
|
|
373
|
+
if (((ix - 0x3ff00000) | lowWord(x)) === 0) return x * PIO2_HI
|
|
374
|
+
return 0 / (x - x)
|
|
375
|
+
}
|
|
376
|
+
if (ix < 0x3fe00000) {
|
|
377
|
+
// |x| < 0.5
|
|
378
|
+
if (ix < 0x3e500000 && ix >= 0x00100000) return x
|
|
379
|
+
return x + x * asinRatio(x * x)
|
|
380
|
+
}
|
|
381
|
+
// 0.5 <= |x| < 1
|
|
382
|
+
const z = (1 - Math.abs(x)) * 0.5
|
|
383
|
+
const s = Math.sqrt(z)
|
|
384
|
+
const r = asinRatio(z)
|
|
385
|
+
let result: number
|
|
386
|
+
if (ix >= 0x3fef3333) {
|
|
387
|
+
// |x| > 0.975
|
|
388
|
+
result = PIO2_HI - (2 * (s + s * r) - PIO2_LO)
|
|
389
|
+
} else {
|
|
390
|
+
const f = clearLow(s)
|
|
391
|
+
const c = (z - f * f) / (s + f)
|
|
392
|
+
result = 0.5 * PIO2_HI - (2 * s * r - (PIO2_LO - 2 * c) - (0.5 * PIO2_HI - 2 * f))
|
|
393
|
+
}
|
|
394
|
+
return hx < 0 ? -result : result
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
export const acos = (x: number): number => {
|
|
398
|
+
const hx = highWord(x)
|
|
399
|
+
const ix = hx & 0x7fffffff
|
|
400
|
+
if (ix >= 0x3ff00000) {
|
|
401
|
+
// |x| >= 1 or NaN
|
|
402
|
+
if (((ix - 0x3ff00000) | lowWord(x)) === 0) return hx < 0 ? 2 * PIO2_HI : 0
|
|
403
|
+
return 0 / (x - x)
|
|
404
|
+
}
|
|
405
|
+
if (ix < 0x3fe00000) {
|
|
406
|
+
// |x| < 0.5
|
|
407
|
+
if (ix <= 0x3c600000) return PIO2_HI // |x| < 2^-57
|
|
408
|
+
return PIO2_HI - (x - (PIO2_LO - x * asinRatio(x * x)))
|
|
409
|
+
}
|
|
410
|
+
if (hx < 0) {
|
|
411
|
+
// x < -0.5
|
|
412
|
+
const z = (1.0 + x) * 0.5
|
|
413
|
+
const s = Math.sqrt(z)
|
|
414
|
+
const w = asinRatio(z) * s - PIO2_LO
|
|
415
|
+
return 2 * (PIO2_HI - (s + w))
|
|
416
|
+
}
|
|
417
|
+
// x > 0.5
|
|
418
|
+
const z = (1.0 - x) * 0.5
|
|
419
|
+
const s = Math.sqrt(z)
|
|
420
|
+
const df = clearLow(s)
|
|
421
|
+
const c = (z - df * df) / (s + df)
|
|
422
|
+
const w = asinRatio(z) * s + c
|
|
423
|
+
return 2 * (df + w)
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const ATAN_HI = [
|
|
427
|
+
4.63647609000806093515e-01,
|
|
428
|
+
7.85398163397448278999e-01,
|
|
429
|
+
9.82793723247329054082e-01,
|
|
430
|
+
1.57079632679489655800e+00
|
|
431
|
+
] as const
|
|
432
|
+
const ATAN_LO = [
|
|
433
|
+
2.26987774529616870924e-17,
|
|
434
|
+
3.06161699786838301793e-17,
|
|
435
|
+
1.39033110312309984516e-17,
|
|
436
|
+
6.12323399573676603587e-17
|
|
437
|
+
] as const
|
|
438
|
+
const AT = [
|
|
439
|
+
3.33333333333329318027e-01,
|
|
440
|
+
-1.99999999998764832476e-01,
|
|
441
|
+
1.42857142725034663711e-01,
|
|
442
|
+
-1.11111104054623557880e-01,
|
|
443
|
+
9.09088713343650656196e-02,
|
|
444
|
+
-7.69187620504482999495e-02,
|
|
445
|
+
6.66107313738753120669e-02,
|
|
446
|
+
-5.83357013379057348645e-02,
|
|
447
|
+
4.97687799461593236017e-02,
|
|
448
|
+
-3.65315727442169155270e-02,
|
|
449
|
+
1.62858201153657823623e-02
|
|
450
|
+
] as const
|
|
451
|
+
|
|
452
|
+
export const atan = (xIn: number): number => {
|
|
453
|
+
let x = xIn
|
|
454
|
+
const hx = highWord(x)
|
|
455
|
+
const negative = hx < 0
|
|
456
|
+
const ix = hx & 0x7fffffff
|
|
457
|
+
if (ix >= 0x44100000) {
|
|
458
|
+
// |x| >= 2^66 or NaN
|
|
459
|
+
if (x !== x) return x
|
|
460
|
+
return negative ? -ATAN_HI[3] : ATAN_HI[3]
|
|
461
|
+
}
|
|
462
|
+
let id: number
|
|
463
|
+
if (ix < 0x3fdc0000) {
|
|
464
|
+
// |x| < 0.4375
|
|
465
|
+
if (ix < 0x3e400000) return x // |x| < 2^-27
|
|
466
|
+
id = -1
|
|
467
|
+
} else {
|
|
468
|
+
x = Math.abs(x)
|
|
469
|
+
if (ix < 0x3ff30000) {
|
|
470
|
+
// |x| < 1.1875
|
|
471
|
+
if (ix < 0x3fe60000) {
|
|
472
|
+
// 7/16 <= |x| < 11/16
|
|
473
|
+
id = 0
|
|
474
|
+
x = (2.0 * x - 1.0) / (2.0 + x)
|
|
475
|
+
} else {
|
|
476
|
+
// 11/16 <= |x| < 19/16
|
|
477
|
+
id = 1
|
|
478
|
+
x = (x - 1.0) / (x + 1.0)
|
|
479
|
+
}
|
|
480
|
+
} else if (ix < 0x40038000) {
|
|
481
|
+
// |x| < 2.4375
|
|
482
|
+
id = 2
|
|
483
|
+
x = (x - 1.5) / (1.0 + 1.5 * x)
|
|
484
|
+
} else {
|
|
485
|
+
// 2.4375 <= |x| < 2^66
|
|
486
|
+
id = 3
|
|
487
|
+
x = -1.0 / x
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
const z = x * x
|
|
491
|
+
const w = z * z
|
|
492
|
+
const s1 = z * (AT[0] + w * (AT[2] + w * (AT[4] + w * (AT[6] + w * (AT[8] + w * AT[10])))))
|
|
493
|
+
const s2 = w * (AT[1] + w * (AT[3] + w * (AT[5] + w * (AT[7] + w * AT[9]))))
|
|
494
|
+
if (id < 0) return x - x * (s1 + s2)
|
|
495
|
+
const result = ATAN_HI[id]! - ((x * (s1 + s2) - ATAN_LO[id]!) - x)
|
|
496
|
+
return negative ? -result : result
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
const PI = 3.1415926535897931160e+00
|
|
500
|
+
const PI_LO = 1.2246467991473531772e-16
|
|
501
|
+
|
|
502
|
+
export const atan2 = (y: number, x: number): number => {
|
|
503
|
+
if (x !== x || y !== y) return x + y
|
|
504
|
+
const hx = highWord(x)
|
|
505
|
+
const lx = lowWord(x)
|
|
506
|
+
const hy = highWord(y)
|
|
507
|
+
const ly = lowWord(y)
|
|
508
|
+
if (((hx - 0x3ff00000) | lx) === 0) return atan(y) // x = 1
|
|
509
|
+
const m = ((hy >>> 31) & 1) | ((hx >>> 30) & 2) // 2·sign(x) + sign(y)
|
|
510
|
+
const ix = hx & 0x7fffffff
|
|
511
|
+
const iy = hy & 0x7fffffff
|
|
512
|
+
if ((iy | ly) === 0) {
|
|
513
|
+
// y = ±0
|
|
514
|
+
switch (m) {
|
|
515
|
+
case 0:
|
|
516
|
+
case 1:
|
|
517
|
+
return y
|
|
518
|
+
case 2:
|
|
519
|
+
return PI
|
|
520
|
+
default:
|
|
521
|
+
return -PI
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
if ((ix | lx) === 0) return m & 1 ? -PI / 2 : PI / 2 // x = ±0
|
|
525
|
+
if (ix === 0x7ff00000) {
|
|
526
|
+
// x = ±Infinity
|
|
527
|
+
if (iy === 0x7ff00000) {
|
|
528
|
+
switch (m) {
|
|
529
|
+
case 0:
|
|
530
|
+
return PI / 4
|
|
531
|
+
case 1:
|
|
532
|
+
return -PI / 4
|
|
533
|
+
case 2:
|
|
534
|
+
return 3 * PI / 4
|
|
535
|
+
default:
|
|
536
|
+
return -3 * PI / 4
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
switch (m) {
|
|
540
|
+
case 0:
|
|
541
|
+
return 0.0
|
|
542
|
+
case 1:
|
|
543
|
+
return -0.0
|
|
544
|
+
case 2:
|
|
545
|
+
return PI
|
|
546
|
+
default:
|
|
547
|
+
return -PI
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
// |y/x| > 2^64
|
|
551
|
+
if (ix + (64 << 20) < iy || iy === 0x7ff00000) return m & 1 ? -PI / 2 : PI / 2
|
|
552
|
+
// atan(|y/x|) without spurious underflow
|
|
553
|
+
const z = (m & 2) !== 0 && iy + (64 << 20) < ix ? 0 : atan(Math.abs(y / x))
|
|
554
|
+
switch (m) {
|
|
555
|
+
case 0:
|
|
556
|
+
return z
|
|
557
|
+
case 1:
|
|
558
|
+
return -z
|
|
559
|
+
case 2:
|
|
560
|
+
return PI - (z - PI_LO)
|
|
561
|
+
default:
|
|
562
|
+
return (z - PI_LO) - PI
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// ---------------------------------------------------------------------------
|
|
567
|
+
// Exponential functions
|
|
568
|
+
|
|
569
|
+
const LN2_HI = 6.93147180369123816490e-01
|
|
570
|
+
const LN2_LO = 1.90821492927058770002e-10
|
|
571
|
+
const INV_LN2 = 1.44269504088896338700e+00
|
|
572
|
+
const P1 = 1.66666666666666019037e-01
|
|
573
|
+
const P2 = -2.77777777770155933842e-03
|
|
574
|
+
const P3 = 6.61375632143793436117e-05
|
|
575
|
+
const P4 = -1.65339022054652515390e-06
|
|
576
|
+
const P5 = 4.13813679705723846039e-08
|
|
577
|
+
|
|
578
|
+
export const exp = (xIn: number): number => {
|
|
579
|
+
let x = xIn
|
|
580
|
+
const hx = highWord(x)
|
|
581
|
+
const negative = hx < 0
|
|
582
|
+
const ix = hx & 0x7fffffff
|
|
583
|
+
if (ix >= 0x4086232b) {
|
|
584
|
+
// |x| >= 708.39 or NaN
|
|
585
|
+
if (x !== x) return x
|
|
586
|
+
if (x > 709.782712893383973096) return x * TWO_1023 // overflow
|
|
587
|
+
if (x < -745.13321910194110842) return 0 // underflow
|
|
588
|
+
}
|
|
589
|
+
if (x === 1) return 2.718281828459045 // Math.E: the reduction below lands 1 ulp above it
|
|
590
|
+
let hi = 0
|
|
591
|
+
let lo = 0
|
|
592
|
+
let k = 0
|
|
593
|
+
if (ix > 0x3fd62e42) {
|
|
594
|
+
// |x| > 0.5·ln2
|
|
595
|
+
if (ix >= 0x3ff0a2b2) {
|
|
596
|
+
// |x| >= 1.5·ln2
|
|
597
|
+
k = (INV_LN2 * x + (negative ? -0.5 : 0.5)) | 0
|
|
598
|
+
} else {
|
|
599
|
+
k = negative ? -1 : 1
|
|
600
|
+
}
|
|
601
|
+
hi = x - k * LN2_HI
|
|
602
|
+
lo = k * LN2_LO
|
|
603
|
+
x = hi - lo
|
|
604
|
+
} else if (ix > 0x3e300000) {
|
|
605
|
+
// |x| > 2^-28
|
|
606
|
+
hi = x
|
|
607
|
+
} else {
|
|
608
|
+
return 1 + x
|
|
609
|
+
}
|
|
610
|
+
const xx = x * x
|
|
611
|
+
const c = x - xx * (P1 + xx * (P2 + xx * (P3 + xx * (P4 + xx * P5))))
|
|
612
|
+
const y = 1 + (x * c / (2 - c) - lo + hi)
|
|
613
|
+
return k === 0 ? y : scalbn(y, k)
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
const O_THRESHOLD = 7.09782712893383973096e+02
|
|
617
|
+
const Q1 = -3.33333333333331316428e-02
|
|
618
|
+
const Q2 = 1.58730158725481460165e-03
|
|
619
|
+
const Q3 = -7.93650757867487942473e-05
|
|
620
|
+
const Q4 = 4.00821782732936239552e-06
|
|
621
|
+
const Q5 = -2.01099218183624371326e-07
|
|
622
|
+
|
|
623
|
+
/** e^x − 1, accurate near 0. */
|
|
624
|
+
export const expm1 = (xIn: number): number => {
|
|
625
|
+
let x = xIn
|
|
626
|
+
const hx = highWord(x)
|
|
627
|
+
const negative = hx < 0
|
|
628
|
+
const ix = hx & 0x7fffffff
|
|
629
|
+
if (ix >= 0x4043687a) {
|
|
630
|
+
// |x| >= 56·ln2
|
|
631
|
+
if (x !== x) return x
|
|
632
|
+
if (negative) return -1
|
|
633
|
+
if (x > O_THRESHOLD) return x * TWO_1023
|
|
634
|
+
}
|
|
635
|
+
let k: number
|
|
636
|
+
let c = 0
|
|
637
|
+
if (ix > 0x3fd62e42) {
|
|
638
|
+
// |x| > 0.5·ln2
|
|
639
|
+
let hi: number
|
|
640
|
+
let lo: number
|
|
641
|
+
if (ix < 0x3ff0a2b2) {
|
|
642
|
+
// |x| < 1.5·ln2
|
|
643
|
+
if (!negative) {
|
|
644
|
+
hi = x - LN2_HI
|
|
645
|
+
lo = LN2_LO
|
|
646
|
+
k = 1
|
|
647
|
+
} else {
|
|
648
|
+
hi = x + LN2_HI
|
|
649
|
+
lo = -LN2_LO
|
|
650
|
+
k = -1
|
|
651
|
+
}
|
|
652
|
+
} else {
|
|
653
|
+
k = (INV_LN2 * x + (negative ? -0.5 : 0.5)) | 0
|
|
654
|
+
hi = x - k * LN2_HI
|
|
655
|
+
lo = k * LN2_LO
|
|
656
|
+
}
|
|
657
|
+
x = hi - lo
|
|
658
|
+
c = (hi - x) - lo
|
|
659
|
+
} else if (ix < 0x3c900000) {
|
|
660
|
+
return x // |x| < 2^-54
|
|
661
|
+
} else {
|
|
662
|
+
k = 0
|
|
663
|
+
}
|
|
664
|
+
const hfx = 0.5 * x
|
|
665
|
+
const hxs = x * hfx
|
|
666
|
+
const r1 = 1.0 + hxs * (Q1 + hxs * (Q2 + hxs * (Q3 + hxs * (Q4 + hxs * Q5))))
|
|
667
|
+
const t = 3.0 - r1 * hfx
|
|
668
|
+
let e = hxs * ((r1 - t) / (6.0 - x * t))
|
|
669
|
+
if (k === 0) return x - (x * e - hxs)
|
|
670
|
+
e = x * (e - c) - c
|
|
671
|
+
e -= hxs
|
|
672
|
+
if (k === -1) return 0.5 * (x - e) - 0.5
|
|
673
|
+
if (k === 1) {
|
|
674
|
+
if (x < -0.25) return -2.0 * (e - (x + 0.5))
|
|
675
|
+
return 1.0 + 2.0 * (x - e)
|
|
676
|
+
}
|
|
677
|
+
if (k < 0 || k > 56) {
|
|
678
|
+
const y = x - e + 1.0
|
|
679
|
+
return (k === 1024 ? y * 2.0 * TWO_1023 : y * fromWords((0x3ff + k) << 20, 0)) - 1.0
|
|
680
|
+
}
|
|
681
|
+
const twopk = fromWords((0x3ff + k) << 20, 0)
|
|
682
|
+
const twomk = fromWords((0x3ff - k) << 20, 0)
|
|
683
|
+
if (k < 20) return (x - e + (1 - twomk)) * twopk
|
|
684
|
+
return (x - (e + twomk) + 1) * twopk
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
export const tanh = (xIn: number): number => {
|
|
688
|
+
const negative = highWord(xIn) < 0
|
|
689
|
+
const x = Math.abs(xIn)
|
|
690
|
+
const w = highWord(x)
|
|
691
|
+
let t: number
|
|
692
|
+
if (w > 0x3fe193ea) {
|
|
693
|
+
// |x| > log(3)/2 or NaN
|
|
694
|
+
if (w > 0x40340000) {
|
|
695
|
+
t = 1 - 0 / x // |x| > 20 or NaN
|
|
696
|
+
} else {
|
|
697
|
+
t = expm1(2 * x)
|
|
698
|
+
t = 1 - 2 / (t + 2)
|
|
699
|
+
}
|
|
700
|
+
} else if (w > 0x3fd058ae) {
|
|
701
|
+
// |x| > log(5/3)/2
|
|
702
|
+
t = expm1(2 * x)
|
|
703
|
+
t = t / (t + 2)
|
|
704
|
+
} else if (w >= 0x00100000) {
|
|
705
|
+
t = expm1(-2 * x)
|
|
706
|
+
t = -t / (t + 2)
|
|
707
|
+
} else {
|
|
708
|
+
t = x // subnormal
|
|
709
|
+
}
|
|
710
|
+
return negative ? -t : t
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
// ---------------------------------------------------------------------------
|
|
714
|
+
// Power
|
|
715
|
+
|
|
716
|
+
const BP = [1.0, 1.5] as const
|
|
717
|
+
const DP_H = [0.0, 5.84962487220764160156e-01] as const
|
|
718
|
+
const DP_L = [0.0, 1.35003920212974897128e-08] as const
|
|
719
|
+
const HUGE = 1.0e300
|
|
720
|
+
const TINY = 1.0e-300
|
|
721
|
+
const L1 = 5.99999999999994648725e-01
|
|
722
|
+
const L2 = 4.28571428578550184252e-01
|
|
723
|
+
const L3 = 3.33333329818377432918e-01
|
|
724
|
+
const L4 = 2.72728123808534006489e-01
|
|
725
|
+
const L5 = 2.30660745775561754067e-01
|
|
726
|
+
const L6 = 2.06975017800338417784e-01
|
|
727
|
+
const LG2 = 6.93147180559945286227e-01
|
|
728
|
+
const LG2_H = 6.93147182464599609375e-01
|
|
729
|
+
const LG2_L = -1.90465429995776804525e-09
|
|
730
|
+
const OVT = 8.0085662595372944372e-17
|
|
731
|
+
const CP = 9.61796693925975554329e-01
|
|
732
|
+
const CP_H = 9.61796700954437255859e-01
|
|
733
|
+
const CP_L = -7.02846165095275826516e-09
|
|
734
|
+
const IVLN2 = 1.44269504088896338700e+00
|
|
735
|
+
const IVLN2_H = 1.44269502162933349609e+00
|
|
736
|
+
const IVLN2_L = 1.92596299112661746887e-08
|
|
737
|
+
|
|
738
|
+
export const pow = (x: number, y: number): number => {
|
|
739
|
+
// ECMAScript Number::exponentiate, where it differs from C pow.
|
|
740
|
+
if (y !== y) return NaN
|
|
741
|
+
if (y === 0) return 1
|
|
742
|
+
if (x !== x) return NaN
|
|
743
|
+
const hx = highWord(x)
|
|
744
|
+
const lx = lowWord(x)
|
|
745
|
+
const hy = highWord(y)
|
|
746
|
+
const ly = lowWord(y)
|
|
747
|
+
let ix = hx & 0x7fffffff
|
|
748
|
+
const iy = hy & 0x7fffffff
|
|
749
|
+
if (iy === 0x7ff00000 && ly === 0 && ((ix - 0x3ff00000) | lx) === 0) return NaN // (±1) ** ±Infinity
|
|
750
|
+
if (hx === 0x3ff00000 && lx === 0) return 1.0 // 1 ** y
|
|
751
|
+
|
|
752
|
+
// yisint: 0 when y is not an integer, 1 when odd, 2 when even (only when x < 0).
|
|
753
|
+
let yisint = 0
|
|
754
|
+
if (hx < 0) {
|
|
755
|
+
if (iy >= 0x43400000) {
|
|
756
|
+
yisint = 2
|
|
757
|
+
} else if (iy >= 0x3ff00000) {
|
|
758
|
+
const e = (iy >> 20) - 0x3ff
|
|
759
|
+
if (e > 20) {
|
|
760
|
+
const j = ly >>> (52 - e)
|
|
761
|
+
if (((j << (52 - e)) >>> 0) === ly) yisint = 2 - (j & 1)
|
|
762
|
+
} else if (ly === 0) {
|
|
763
|
+
const j = iy >> (20 - e)
|
|
764
|
+
if ((j << (20 - e)) === iy) yisint = 2 - (j & 1)
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
if (ly === 0) {
|
|
770
|
+
if (iy === 0x7ff00000) {
|
|
771
|
+
// y = ±Infinity
|
|
772
|
+
if (ix >= 0x3ff00000) return hy >= 0 ? y : 0.0 // (|x| > 1) ** ±Infinity
|
|
773
|
+
return hy >= 0 ? 0.0 : -y // (|x| < 1) ** ±Infinity
|
|
774
|
+
}
|
|
775
|
+
if (iy === 0x3ff00000) return hy >= 0 ? x : 1 / x // y = ±1
|
|
776
|
+
if (hy === 0x40000000) return x * x // y = 2
|
|
777
|
+
if (hy === 0x3fe00000 && hx >= 0) return Math.sqrt(x) // y = 0.5, x >= +0
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
let ax = Math.abs(x)
|
|
781
|
+
if (lx === 0 && (ix === 0x7ff00000 || ix === 0 || ix === 0x3ff00000)) {
|
|
782
|
+
// x = ±0, ±Infinity, ±1
|
|
783
|
+
let z = ax
|
|
784
|
+
if (hy < 0) z = 1.0 / z
|
|
785
|
+
if (hx < 0) {
|
|
786
|
+
if (((ix - 0x3ff00000) | yisint) === 0) {
|
|
787
|
+
z = (z - z) / (z - z) // (-1) ** non-integer
|
|
788
|
+
} else if (yisint === 1) {
|
|
789
|
+
z = -z
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
return z
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
let s = 1.0 // sign of the result
|
|
796
|
+
if (hx < 0) {
|
|
797
|
+
if (yisint === 0) return (x - x) / (x - x) // (x < 0) ** non-integer
|
|
798
|
+
if (yisint === 1) s = -1.0
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
let t1: number
|
|
802
|
+
let t2: number
|
|
803
|
+
if (iy > 0x41e00000) {
|
|
804
|
+
// |y| > 2^31
|
|
805
|
+
if (iy > 0x43f00000) {
|
|
806
|
+
// |y| > 2^64: must overflow or underflow
|
|
807
|
+
if (ix <= 0x3fefffff) return hy < 0 ? HUGE * HUGE : TINY * TINY
|
|
808
|
+
if (ix >= 0x3ff00000) return hy > 0 ? HUGE * HUGE : TINY * TINY
|
|
809
|
+
}
|
|
810
|
+
// Overflow or underflow when x is not close to one.
|
|
811
|
+
if (ix < 0x3fefffff) return hy < 0 ? s * HUGE * HUGE : s * TINY * TINY
|
|
812
|
+
if (ix > 0x3ff00000) return hy > 0 ? s * HUGE * HUGE : s * TINY * TINY
|
|
813
|
+
// |1 - x| <= 2^-20: log(x) by x - x^2/2 + x^3/3 - x^4/4
|
|
814
|
+
const t = ax - 1.0
|
|
815
|
+
const w = (t * t) * (0.5 - t * (0.3333333333333333333333 - t * 0.25))
|
|
816
|
+
const u = IVLN2_H * t
|
|
817
|
+
const v = t * IVLN2_L - w * IVLN2
|
|
818
|
+
t1 = clearLow(u + v)
|
|
819
|
+
t2 = v - (t1 - u)
|
|
820
|
+
} else {
|
|
821
|
+
let n = 0
|
|
822
|
+
if (ix < 0x00100000) {
|
|
823
|
+
// subnormal x
|
|
824
|
+
ax *= TWO_53
|
|
825
|
+
n -= 53
|
|
826
|
+
ix = highWord(ax)
|
|
827
|
+
}
|
|
828
|
+
n += (ix >> 20) - 0x3ff
|
|
829
|
+
const j = ix & 0x000fffff
|
|
830
|
+
ix = j | 0x3ff00000
|
|
831
|
+
let k: 0 | 1
|
|
832
|
+
if (j <= 0x3988e) {
|
|
833
|
+
k = 0 // |x| < sqrt(3/2)
|
|
834
|
+
} else if (j < 0xbb67a) {
|
|
835
|
+
k = 1 // |x| < sqrt(3)
|
|
836
|
+
} else {
|
|
837
|
+
k = 0
|
|
838
|
+
n += 1
|
|
839
|
+
ix -= 0x00100000
|
|
840
|
+
}
|
|
841
|
+
ax = fromWords(ix, lowWord(ax))
|
|
842
|
+
// ss = s_h + s_l = (x - 1)/(x + 1) or (x - 1.5)/(x + 1.5)
|
|
843
|
+
let u = ax - BP[k]
|
|
844
|
+
let v = 1.0 / (ax + BP[k])
|
|
845
|
+
const ss = u * v
|
|
846
|
+
const sH = clearLow(ss)
|
|
847
|
+
let tH = fromWords(((ix >> 1) | 0x20000000) + 0x00080000 + (k << 18), 0)
|
|
848
|
+
let tL = ax - (tH - BP[k])
|
|
849
|
+
const sL = v * ((u - sH * tH) - sH * tL)
|
|
850
|
+
// log(ax)
|
|
851
|
+
let s2 = ss * ss
|
|
852
|
+
let r = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6)))))
|
|
853
|
+
r += sL * (sH + ss)
|
|
854
|
+
s2 = sH * sH
|
|
855
|
+
tH = clearLow(3.0 + s2 + r)
|
|
856
|
+
tL = r - ((tH - 3.0) - s2)
|
|
857
|
+
u = sH * tH
|
|
858
|
+
v = sL * tH + tL * ss
|
|
859
|
+
const pH = clearLow(u + v)
|
|
860
|
+
const pL = v - (pH - u)
|
|
861
|
+
const zH = CP_H * pH
|
|
862
|
+
const zL = CP_L * pH + pL * CP + DP_L[k]
|
|
863
|
+
const t = n
|
|
864
|
+
t1 = clearLow(((zH + zL) + DP_H[k]) + t)
|
|
865
|
+
t2 = zL - (((t1 - t) - DP_H[k]) - zH)
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
// (y1 + y2)·(t1 + t2)
|
|
869
|
+
const y1 = clearLow(y)
|
|
870
|
+
const pL = (y - y1) * t1 + y * t2
|
|
871
|
+
let pH = y1 * t1
|
|
872
|
+
let z = pL + pH
|
|
873
|
+
let j = highWord(z)
|
|
874
|
+
const i = lowWord(z)
|
|
875
|
+
if (j >= 0x40900000) {
|
|
876
|
+
// z >= 1024
|
|
877
|
+
if (((j - 0x40900000) | i) !== 0) return s * HUGE * HUGE
|
|
878
|
+
if (pL + OVT > z - pH) return s * HUGE * HUGE
|
|
879
|
+
} else if ((j & 0x7fffffff) >= 0x4090cc00) {
|
|
880
|
+
// z <= -1075
|
|
881
|
+
if (((j - (0xc090cc00 | 0)) | i) !== 0) return s * TINY * TINY
|
|
882
|
+
if (pL <= z - pH) return s * TINY * TINY
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
// 2^(pH + pL)
|
|
886
|
+
const abs = j & 0x7fffffff
|
|
887
|
+
let k = (abs >> 20) - 0x3ff
|
|
888
|
+
let n = 0
|
|
889
|
+
if (abs > 0x3fe00000) {
|
|
890
|
+
// |z| > 0.5: n = [z + 0.5]
|
|
891
|
+
n = j + (0x00100000 >> (k + 1))
|
|
892
|
+
k = ((n & 0x7fffffff) >> 20) - 0x3ff
|
|
893
|
+
const t = fromWords(n & ~(0x000fffff >> k), 0)
|
|
894
|
+
n = ((n & 0x000fffff) | 0x00100000) >> (20 - k)
|
|
895
|
+
if (j < 0) n = -n
|
|
896
|
+
pH -= t
|
|
897
|
+
}
|
|
898
|
+
const t = clearLow(pL + pH)
|
|
899
|
+
const u = t * LG2_H
|
|
900
|
+
const v = (pL - (t - pH)) * LG2 + t * LG2_L
|
|
901
|
+
z = u + v
|
|
902
|
+
const w = v - (z - u)
|
|
903
|
+
const tt = z * z
|
|
904
|
+
const r1 = z - tt * (P1 + tt * (P2 + tt * (P3 + tt * (P4 + tt * P5))))
|
|
905
|
+
const r = (z * r1) / (r1 - 2.0) - (w + z * w)
|
|
906
|
+
z = 1.0 - (r - z)
|
|
907
|
+
j = highWord(z)
|
|
908
|
+
j += n << 20
|
|
909
|
+
if ((j >> 20) <= 0) {
|
|
910
|
+
z = scalbn(z, n) // subnormal result
|
|
911
|
+
} else {
|
|
912
|
+
z = fromWords(j, lowWord(z))
|
|
913
|
+
}
|
|
914
|
+
return s * z
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
// ---------------------------------------------------------------------------
|
|
918
|
+
// hypot
|
|
919
|
+
|
|
920
|
+
const SPLIT = 134217729 // 2^27 + 1
|
|
921
|
+
const TWO_700 = fromWords((700 + 1023) << 20, 0)
|
|
922
|
+
const TWO_M700 = fromWords((-700 + 1023) << 20, 0)
|
|
923
|
+
|
|
924
|
+
export const hypot = (xIn: number, yIn: number): number => {
|
|
925
|
+
let hx = highWord(xIn) & 0x7fffffff
|
|
926
|
+
let lx = lowWord(xIn)
|
|
927
|
+
let hy = highWord(yIn) & 0x7fffffff
|
|
928
|
+
let ly = lowWord(yIn)
|
|
929
|
+
// Arrange |x| >= |y| by their bits, so NaN sorts above Infinity.
|
|
930
|
+
if (hx < hy || (hx === hy && lx < ly)) {
|
|
931
|
+
const th = hx
|
|
932
|
+
const tl = lx
|
|
933
|
+
hx = hy
|
|
934
|
+
lx = ly
|
|
935
|
+
hy = th
|
|
936
|
+
ly = tl
|
|
937
|
+
}
|
|
938
|
+
const ex = hx >>> 20
|
|
939
|
+
const ey = hy >>> 20
|
|
940
|
+
let x = fromWords(hx, lx)
|
|
941
|
+
let y = fromWords(hy, ly)
|
|
942
|
+
if (ey === 0x7ff) return y // hypot(Infinity, NaN) is Infinity
|
|
943
|
+
if (ex === 0x7ff || (hy | ly) === 0) return x
|
|
944
|
+
if (ex - ey > 64) return x + y
|
|
945
|
+
// Scale so xh·xh cannot overflow and xl·xl cannot underflow.
|
|
946
|
+
let z = 1
|
|
947
|
+
if (ex > 0x3ff + 510) {
|
|
948
|
+
z = TWO_700
|
|
949
|
+
x *= TWO_M700
|
|
950
|
+
y *= TWO_M700
|
|
951
|
+
} else if (ey < 0x3ff - 450) {
|
|
952
|
+
z = TWO_M700
|
|
953
|
+
x *= TWO_700
|
|
954
|
+
y *= TWO_700
|
|
955
|
+
}
|
|
956
|
+
// x² and y² as exact double-double sums (Dekker split).
|
|
957
|
+
let c = x * SPLIT
|
|
958
|
+
const xh = x - c + c
|
|
959
|
+
const xl = x - xh
|
|
960
|
+
const hxx = x * x
|
|
961
|
+
const lxx = xh * xh - hxx + 2 * xh * xl + xl * xl
|
|
962
|
+
c = y * SPLIT
|
|
963
|
+
const yh = y - c + c
|
|
964
|
+
const yl = y - yh
|
|
965
|
+
const hyy = y * y
|
|
966
|
+
const lyy = yh * yh - hyy + 2 * yh * yl + yl * yl
|
|
967
|
+
return z * Math.sqrt(lyy + lxx + hyy + hxx)
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
// ---------------------------------------------------------------------------
|
|
971
|
+
// Logarithms
|
|
972
|
+
|
|
973
|
+
const LOG1 = 6.666666666666735130e-01
|
|
974
|
+
const LOG2 = 3.999999999940941908e-01
|
|
975
|
+
const LOG3 = 2.857142874366239149e-01
|
|
976
|
+
const LOG4 = 2.222219843214978396e-01
|
|
977
|
+
const LOG5 = 1.818357216161805012e-01
|
|
978
|
+
const LOG6 = 1.531383769920937332e-01
|
|
979
|
+
const LOG7 = 1.479819860511658591e-01
|
|
980
|
+
const TWO_54 = fromWords(0x43500000, 0)
|
|
981
|
+
|
|
982
|
+
let logK = 0
|
|
983
|
+
let logF = 0
|
|
984
|
+
|
|
985
|
+
/**
|
|
986
|
+
* Splits a positive finite non-unit `x` into `2^logK · (1 + logF)` with
|
|
987
|
+
* `1 + logF` in [√2/2, √2]. Returns a result for the special cases
|
|
988
|
+
* (±0, negative, NaN, Infinity), or `undefined` once split.
|
|
989
|
+
*/
|
|
990
|
+
const logSplit = (xIn: number): number | undefined => {
|
|
991
|
+
let x = xIn
|
|
992
|
+
let hx = highWord(x) >>> 0
|
|
993
|
+
let k = 0
|
|
994
|
+
if (hx < 0x00100000 || hx >>> 31 !== 0) {
|
|
995
|
+
if (x === 0) return -1 / (x * x) // log(±0) = -Infinity
|
|
996
|
+
if (hx >>> 31 !== 0) return (x - x) / 0.0 // log(negative) = NaN
|
|
997
|
+
k -= 54 // subnormal: scale up
|
|
998
|
+
x *= TWO_54
|
|
999
|
+
hx = highWord(x) >>> 0
|
|
1000
|
+
} else if (hx >= 0x7ff00000) {
|
|
1001
|
+
return x // Infinity or NaN
|
|
1002
|
+
} else if (hx === 0x3ff00000 && lowWord(x) === 0) {
|
|
1003
|
+
return 0 // log(1) = +0
|
|
1004
|
+
}
|
|
1005
|
+
hx += 0x3ff00000 - 0x3fe6a09e
|
|
1006
|
+
k += (hx >>> 20) - 0x3ff
|
|
1007
|
+
hx = (hx & 0x000fffff) + 0x3fe6a09e
|
|
1008
|
+
logK = k
|
|
1009
|
+
logF = fromWords(hx, lowWord(x)) - 1.0
|
|
1010
|
+
return undefined
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
/** s·(hfsq + R) of the log kernel on f = logF. */
|
|
1014
|
+
const logKernel = (f: number, hfsq: number): number => {
|
|
1015
|
+
const s = f / (2.0 + f)
|
|
1016
|
+
const z = s * s
|
|
1017
|
+
const w = z * z
|
|
1018
|
+
const t1 = w * (LOG2 + w * (LOG4 + w * LOG6))
|
|
1019
|
+
const t2 = z * (LOG1 + w * (LOG3 + w * (LOG5 + w * LOG7)))
|
|
1020
|
+
return s * (hfsq + t2 + t1)
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
export const log = (x: number): number => {
|
|
1024
|
+
const special = logSplit(x)
|
|
1025
|
+
if (special !== undefined) return special
|
|
1026
|
+
const f = logF
|
|
1027
|
+
const hfsq = 0.5 * f * f
|
|
1028
|
+
const dk = logK
|
|
1029
|
+
return logKernel(f, hfsq) + dk * LN2_LO - hfsq + f + dk * LN2_HI
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
const IVLN2HI = 1.44269504072144627571e+00
|
|
1033
|
+
const IVLN2LO = 1.67517131648865118353e-10
|
|
1034
|
+
|
|
1035
|
+
export const log2 = (x: number): number => {
|
|
1036
|
+
const special = logSplit(x)
|
|
1037
|
+
if (special !== undefined) return special
|
|
1038
|
+
const f = logF
|
|
1039
|
+
const hfsq = 0.5 * f * f
|
|
1040
|
+
const hi = clearLow(f - hfsq)
|
|
1041
|
+
const lo = f - hi - hfsq + logKernel(f, hfsq)
|
|
1042
|
+
let valHi = hi * IVLN2HI
|
|
1043
|
+
let valLo = (lo + hi) * IVLN2LO + lo * IVLN2HI
|
|
1044
|
+
const y = logK
|
|
1045
|
+
const w = y + valHi
|
|
1046
|
+
valLo += (y - w) + valHi
|
|
1047
|
+
valHi = w
|
|
1048
|
+
return valLo + valHi
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
const IVLN10HI = 4.34294481878168880939e-01
|
|
1052
|
+
const IVLN10LO = 2.50829467116452752298e-11
|
|
1053
|
+
const LOG10_2HI = 3.01029995663611771306e-01
|
|
1054
|
+
const LOG10_2LO = 3.69423907715893078616e-13
|
|
1055
|
+
|
|
1056
|
+
export const log10 = (x: number): number => {
|
|
1057
|
+
const special = logSplit(x)
|
|
1058
|
+
if (special !== undefined) return special
|
|
1059
|
+
const f = logF
|
|
1060
|
+
const hfsq = 0.5 * f * f
|
|
1061
|
+
const hi = clearLow(f - hfsq)
|
|
1062
|
+
const lo = f - hi - hfsq + logKernel(f, hfsq)
|
|
1063
|
+
let valHi = hi * IVLN10HI
|
|
1064
|
+
const dk = logK
|
|
1065
|
+
const y = dk * LOG10_2HI
|
|
1066
|
+
let valLo = dk * LOG10_2LO + (lo + hi) * IVLN10LO + lo * IVLN10HI
|
|
1067
|
+
const w = y + valHi
|
|
1068
|
+
valLo += (y - w) + valHi
|
|
1069
|
+
valHi = w
|
|
1070
|
+
return valLo + valHi
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
export const log1p = (x: number): number => {
|
|
1074
|
+
const hx = highWord(x) >>> 0
|
|
1075
|
+
let k = 1
|
|
1076
|
+
let c = 0
|
|
1077
|
+
let f = 0
|
|
1078
|
+
if (hx < 0x3fda827a || hx >>> 31 !== 0) {
|
|
1079
|
+
// 1 + x < √2
|
|
1080
|
+
if (hx >= 0xbff00000) {
|
|
1081
|
+
// x <= -1
|
|
1082
|
+
if (x === -1) return x / 0.0 // -Infinity
|
|
1083
|
+
return (x - x) / 0.0 // NaN
|
|
1084
|
+
}
|
|
1085
|
+
if (((hx << 1) >>> 0) < 0x79400000) return x // |x| < 2^-53
|
|
1086
|
+
if (hx <= 0xbfd2bec4) {
|
|
1087
|
+
// √2/2 <= 1 + x < √2
|
|
1088
|
+
k = 0
|
|
1089
|
+
f = x
|
|
1090
|
+
}
|
|
1091
|
+
} else if (hx >= 0x7ff00000) {
|
|
1092
|
+
return x
|
|
1093
|
+
}
|
|
1094
|
+
if (k !== 0) {
|
|
1095
|
+
const u = 1 + x
|
|
1096
|
+
let hu = highWord(u) >>> 0
|
|
1097
|
+
hu += 0x3ff00000 - 0x3fe6a09e
|
|
1098
|
+
k = (hu >>> 20) - 0x3ff
|
|
1099
|
+
// Correction term ~ log(1 + x) - log(u), avoiding underflow in c/u.
|
|
1100
|
+
if (k < 54) {
|
|
1101
|
+
c = k >= 2 ? 1 - (u - x) : x - (u - 1)
|
|
1102
|
+
c /= u
|
|
1103
|
+
} else {
|
|
1104
|
+
c = 0
|
|
1105
|
+
}
|
|
1106
|
+
hu = (hu & 0x000fffff) + 0x3fe6a09e
|
|
1107
|
+
f = fromWords(hu, lowWord(u)) - 1
|
|
1108
|
+
}
|
|
1109
|
+
const hfsq = 0.5 * f * f
|
|
1110
|
+
const dk = k
|
|
1111
|
+
return logKernel(f, hfsq) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
// ---------------------------------------------------------------------------
|
|
1115
|
+
// Hyperbolic functions
|
|
1116
|
+
|
|
1117
|
+
const EXPO2_KLN2 = fromWords(0x40962066, 0x151add8b) // 2043·ln2 (musl __expo2)
|
|
1118
|
+
const EXPO2_SCALE = fromWords((0x3ff + 1021) << 20, 0) // 2^1021
|
|
1119
|
+
|
|
1120
|
+
/** exp(x)/2·sign for x > log(DBL_MAX): exp(x - 2043·ln2)·2^2042, without overflowing early. */
|
|
1121
|
+
const expo2 = (x: number, sign: number): number => exp(x - EXPO2_KLN2) * (sign * EXPO2_SCALE) * EXPO2_SCALE
|
|
1122
|
+
|
|
1123
|
+
export const sinh = (x: number): number => {
|
|
1124
|
+
const h = highWord(x) < 0 ? -0.5 : 0.5
|
|
1125
|
+
const absx = Math.abs(x)
|
|
1126
|
+
const w = highWord(absx)
|
|
1127
|
+
if (w < 0x40862e42) {
|
|
1128
|
+
// |x| < log(DBL_MAX)
|
|
1129
|
+
const t = expm1(absx)
|
|
1130
|
+
if (w < 0x3ff00000) {
|
|
1131
|
+
if (w < 0x3ff00000 - (26 << 20)) return x
|
|
1132
|
+
return h * (2 * t - t * t / (t + 1))
|
|
1133
|
+
}
|
|
1134
|
+
return h * (t + t / (t + 1))
|
|
1135
|
+
}
|
|
1136
|
+
return expo2(absx, 2 * h) // overflow or NaN
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
export const cosh = (xIn: number): number => {
|
|
1140
|
+
const x = Math.abs(xIn)
|
|
1141
|
+
const w = highWord(x)
|
|
1142
|
+
if (w < 0x3fe62e42) {
|
|
1143
|
+
// |x| < log(2)
|
|
1144
|
+
if (w < 0x3ff00000 - (26 << 20)) return 1
|
|
1145
|
+
const t = expm1(x)
|
|
1146
|
+
return 1 + t * t / (2 * (1 + t))
|
|
1147
|
+
}
|
|
1148
|
+
if (w < 0x40862e42) {
|
|
1149
|
+
// |x| < log(DBL_MAX)
|
|
1150
|
+
const t = exp(x)
|
|
1151
|
+
return 0.5 * (t + 1 / t)
|
|
1152
|
+
}
|
|
1153
|
+
return expo2(x, 1.0) // overflow or NaN
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
const LN2 = 6.93147180559945286227e-01
|
|
1157
|
+
|
|
1158
|
+
export const asinh = (x: number): number => {
|
|
1159
|
+
const hx = highWord(x)
|
|
1160
|
+
const ix = hx & 0x7fffffff
|
|
1161
|
+
if (ix >= 0x7ff00000) return x + x // Infinity or NaN
|
|
1162
|
+
if (ix < 0x3e300000) return x // |x| < 2^-28
|
|
1163
|
+
let w: number
|
|
1164
|
+
if (ix > 0x41b00000) {
|
|
1165
|
+
// |x| > 2^28
|
|
1166
|
+
w = log(Math.abs(x)) + LN2
|
|
1167
|
+
} else if (ix > 0x40000000) {
|
|
1168
|
+
// 2 < |x| <= 2^28
|
|
1169
|
+
const t = Math.abs(x)
|
|
1170
|
+
w = log(2.0 * t + 1 / (Math.sqrt(x * x + 1) + t))
|
|
1171
|
+
} else {
|
|
1172
|
+
// 2^-28 <= |x| <= 2
|
|
1173
|
+
const t = x * x
|
|
1174
|
+
w = log1p(Math.abs(x) + t / (1 + Math.sqrt(1 + t)))
|
|
1175
|
+
}
|
|
1176
|
+
return hx > 0 ? w : -w
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
export const acosh = (x: number): number => {
|
|
1180
|
+
const hx = highWord(x)
|
|
1181
|
+
if (hx < 0x3ff00000) return (x - x) / (x - x) // x < 1 or negative NaN
|
|
1182
|
+
if (hx >= 0x41b00000) {
|
|
1183
|
+
// x > 2^28
|
|
1184
|
+
if (hx >= 0x7ff00000) return x + x // Infinity or NaN
|
|
1185
|
+
return log(x) + LN2
|
|
1186
|
+
}
|
|
1187
|
+
if (((hx - 0x3ff00000) | lowWord(x)) === 0) return 0 // acosh(1) = 0
|
|
1188
|
+
if (hx > 0x40000000) {
|
|
1189
|
+
// 2 < x <= 2^28
|
|
1190
|
+
const t = x * x
|
|
1191
|
+
return log(2.0 * x - 1 / (x + Math.sqrt(t - 1)))
|
|
1192
|
+
}
|
|
1193
|
+
// 1 < x <= 2
|
|
1194
|
+
const t = x - 1
|
|
1195
|
+
return log1p(t + Math.sqrt(2.0 * t + t * t))
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
export const atanh = (xIn: number): number => {
|
|
1199
|
+
const hx = highWord(xIn)
|
|
1200
|
+
const lx = lowWord(xIn)
|
|
1201
|
+
const ix = hx & 0x7fffffff
|
|
1202
|
+
if ((ix | ((lx | ((-lx) >>> 0)) >>> 31)) > 0x3ff00000) return (xIn - xIn) / (xIn - xIn) // |x| > 1 or NaN
|
|
1203
|
+
if (ix === 0x3ff00000) return xIn / 0 // ±Infinity
|
|
1204
|
+
if (ix < 0x3e300000) return xIn // |x| < 2^-28
|
|
1205
|
+
const x = Math.abs(xIn)
|
|
1206
|
+
let t: number
|
|
1207
|
+
if (ix < 0x3fe00000) {
|
|
1208
|
+
// |x| < 0.5
|
|
1209
|
+
t = x + x
|
|
1210
|
+
t = 0.5 * log1p(t + t * x / (1 - x))
|
|
1211
|
+
} else {
|
|
1212
|
+
t = 0.5 * log1p((x + x) / (1 - x))
|
|
1213
|
+
}
|
|
1214
|
+
return hx >= 0 ? t : -t
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
// ---------------------------------------------------------------------------
|
|
1218
|
+
// Cube root
|
|
1219
|
+
|
|
1220
|
+
const B1 = 715094163 // (1023 - 1023/3 - 0.03306235651)·2^20
|
|
1221
|
+
const B2 = 696219795 // (1023 - 1023/3 - 54/3 - 0.03306235651)·2^20
|
|
1222
|
+
const CP0 = 1.87595182427177009643
|
|
1223
|
+
const CP1 = -1.88497979543377169875
|
|
1224
|
+
const CP2 = 1.621429720105354466140
|
|
1225
|
+
const CP3 = -0.758397934778766047437
|
|
1226
|
+
const CP4 = 0.145996192886612446982
|
|
1227
|
+
|
|
1228
|
+
export const cbrt = (x: number): number => {
|
|
1229
|
+
const high = highWord(x)
|
|
1230
|
+
const sign = high & 0x80000000
|
|
1231
|
+
let hx = high & 0x7fffffff
|
|
1232
|
+
if (hx >= 0x7ff00000) return x + x // Infinity or NaN
|
|
1233
|
+
// Rough cube root to 5 bits.
|
|
1234
|
+
if (hx < 0x00100000) {
|
|
1235
|
+
// zero or subnormal
|
|
1236
|
+
hx = highWord(x * TWO_54) & 0x7fffffff
|
|
1237
|
+
if (hx === 0) return x // ±0
|
|
1238
|
+
hx = Math.floor(hx / 3) + B2
|
|
1239
|
+
} else {
|
|
1240
|
+
hx = Math.floor(hx / 3) + B1
|
|
1241
|
+
}
|
|
1242
|
+
let t = fromWords((sign | hx) >>> 0, 0)
|
|
1243
|
+
// New cube root to 23 bits.
|
|
1244
|
+
let r = (t * t) * (t / x)
|
|
1245
|
+
t = t * ((CP0 + r * (CP1 + r * CP2)) + ((r * r) * r) * (CP3 + r * CP4))
|
|
1246
|
+
// Round t away from zero to 23 bits.
|
|
1247
|
+
const sum = lowWord(t) + 0x80000000
|
|
1248
|
+
const carry = sum >= 0x100000000 ? 1 : 0
|
|
1249
|
+
t = fromWords(((highWord(t) >>> 0) + carry) >>> 0, (sum & 0xc0000000) >>> 0)
|
|
1250
|
+
// One Newton step to 53 bits, error < 0.667 ulp.
|
|
1251
|
+
const s = t * t
|
|
1252
|
+
r = x / s
|
|
1253
|
+
const w = t + t
|
|
1254
|
+
r = (r - t) / (w + r)
|
|
1255
|
+
return t + t * r
|
|
1256
|
+
}
|