@grain/stdlib 0.5.3 → 0.5.5

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.
Files changed (77) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/array.gr +65 -57
  3. package/array.md +54 -6
  4. package/buffer.gr +71 -1
  5. package/buffer.md +142 -0
  6. package/bytes.gr +52 -3
  7. package/bytes.md +117 -0
  8. package/char.gr +23 -20
  9. package/char.md +18 -3
  10. package/immutablemap.gr +493 -0
  11. package/immutablemap.md +479 -0
  12. package/immutablepriorityqueue.gr +44 -16
  13. package/immutablepriorityqueue.md +44 -1
  14. package/immutableset.gr +498 -0
  15. package/immutableset.md +449 -0
  16. package/int32.gr +39 -37
  17. package/int32.md +6 -0
  18. package/int64.gr +39 -37
  19. package/int64.md +6 -0
  20. package/list.gr +33 -24
  21. package/list.md +39 -10
  22. package/map.gr +19 -28
  23. package/marshal.gr +4 -4
  24. package/number.gr +727 -26
  25. package/number.md +345 -23
  26. package/option.gr +30 -26
  27. package/option.md +12 -0
  28. package/package.json +1 -1
  29. package/path.gr +787 -0
  30. package/path.md +727 -0
  31. package/pervasives.gr +3 -4
  32. package/pervasives.md +6 -1
  33. package/priorityqueue.gr +25 -5
  34. package/priorityqueue.md +30 -0
  35. package/queue.gr +22 -7
  36. package/queue.md +18 -1
  37. package/regex.gr +161 -65
  38. package/regex.md +70 -0
  39. package/result.gr +24 -20
  40. package/result.md +12 -0
  41. package/runtime/atof/common.gr +198 -0
  42. package/runtime/atof/common.md +243 -0
  43. package/runtime/atof/decimal.gr +663 -0
  44. package/runtime/atof/decimal.md +59 -0
  45. package/runtime/atof/lemire.gr +264 -0
  46. package/runtime/atof/lemire.md +6 -0
  47. package/runtime/atof/parse.gr +615 -0
  48. package/runtime/atof/parse.md +12 -0
  49. package/runtime/atof/slow.gr +238 -0
  50. package/runtime/atof/slow.md +6 -0
  51. package/runtime/atof/table.gr +2016 -0
  52. package/runtime/atof/table.md +12 -0
  53. package/runtime/{stringUtils.gr → atoi/parse.gr} +1 -1
  54. package/runtime/{stringUtils.md → atoi/parse.md} +1 -1
  55. package/runtime/bigint.gr +7 -7
  56. package/runtime/compare.gr +2 -1
  57. package/runtime/equal.gr +3 -2
  58. package/runtime/exception.gr +9 -5
  59. package/runtime/exception.md +8 -2
  60. package/runtime/gc.gr +2 -1
  61. package/runtime/malloc.gr +1 -3
  62. package/runtime/numberUtils.gr +13 -13
  63. package/runtime/numberUtils.md +6 -0
  64. package/runtime/numbers.gr +123 -39
  65. package/runtime/numbers.md +26 -0
  66. package/runtime/string.gr +4 -2
  67. package/runtime/unsafe/conv.gr +21 -41
  68. package/runtime/unsafe/conv.md +0 -3
  69. package/runtime/unsafe/printWasm.gr +4 -40
  70. package/runtime/utils/printing.gr +3 -3
  71. package/set.gr +25 -25
  72. package/stack.gr +14 -0
  73. package/stack.md +17 -0
  74. package/string.gr +313 -39
  75. package/string.md +99 -0
  76. package/sys/file.gr +1 -1
  77. package/sys/time.gr +4 -4
package/number.gr CHANGED
@@ -16,32 +16,49 @@ import {
16
16
  isInteger,
17
17
  isRational,
18
18
  isBoxedNumber,
19
+ scalbn,
19
20
  } from "runtime/numbers"
20
- import { parseInt } from "runtime/stringUtils"
21
- import { newFloat64, newInt64 } from "runtime/dataStructures"
21
+ import Atoi from "runtime/atoi/parse"
22
+ import Atof from "runtime/atof/parse"
23
+ import { newFloat64, newInt64, allocateString } from "runtime/dataStructures"
22
24
  import Tags from "runtime/unsafe/tags"
25
+ import Exception from "runtime/exception"
23
26
 
24
27
  /**
25
28
  * @section Constants: Number constant values.
26
29
  */
27
30
 
31
+ /**
32
+ * NaN represented as a Number value.
33
+ *
34
+ * @since v0.5.4
35
+ */
36
+ export let nan = 0.0 / 0.0
37
+
38
+ /**
39
+ * Infinity represented as a Number value.
40
+ *
41
+ * @since v0.5.4
42
+ */
43
+ export let infinity = 1.0 / 0.0
44
+
28
45
  /**
29
46
  * Pi represented as a Number value.
30
- *
47
+ *
31
48
  * @since v0.5.2
32
49
  */
33
50
  export let pi = 3.141592653589793
34
51
 
35
52
  /**
36
53
  * Tau represented as a Number value.
37
- *
54
+ *
38
55
  * @since v0.5.2
39
56
  */
40
57
  export let tau = 6.283185307179586
41
58
 
42
59
  /**
43
60
  * Euler's number represented as a Number value.
44
- *
61
+ *
45
62
  * @since v0.5.2
46
63
  */
47
64
  export let e = 2.718281828459045
@@ -94,6 +111,464 @@ export let mul = (*)
94
111
  */
95
112
  export let div = (/)
96
113
 
114
+ // Exponentiation by squaring https://en.wikipedia.org/wiki/Exponentiation_by_squaring special path for int^int
115
+ let rec expBySquaring = (y, x, n) => {
116
+ if (n == 0) {
117
+ 1
118
+ } else if (n == 1) {
119
+ x * y
120
+ } else if (n % 2 == 0) {
121
+ expBySquaring(y, x * x, n / 2)
122
+ } else {
123
+ expBySquaring(x * y, x * x, (n - 1) / 2)
124
+ }
125
+ }
126
+
127
+ // Math.pow is largely based on https://git.musl-libc.org/cgit/musl/tree/src/math/pow.c
128
+ /*
129
+ * ====================================================
130
+ * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
131
+ *
132
+ * Permission to use, copy, modify, and distribute this
133
+ * software is freely granted, provided that this notice
134
+ * is preserved.
135
+ * ====================================================
136
+ */
137
+ /**
138
+ * Computes the exponentiation of the given base and power.
139
+ *
140
+ * @param base: The base number
141
+ * @param power: The exponent number
142
+ * @returns The base raised to the given power
143
+ *
144
+ * @since v0.5.4
145
+ */
146
+ @unsafe
147
+ export let pow = (base, power) => {
148
+ // TODO(#1476): Move this into runtime/numbers.gr
149
+ if (base == 1 && power != 0) {
150
+ 1
151
+ } else if (
152
+ isInteger(WasmI32.fromGrain(base)) && isInteger(WasmI32.fromGrain(power))
153
+ ) {
154
+ if (power < 0) expBySquaring(1, 1 / base, power * -1)
155
+ else expBySquaring(1, base, power)
156
+ } else {
157
+ // TODO(#553): Refactor once we have early return
158
+ // Based on https://git.musl-libc.org/cgit/musl/tree/src/math/pow.c
159
+ let (==) = WasmF64.eq
160
+ let (!=) = WasmF64.ne
161
+ let (<=) = WasmF64.le
162
+ let (/) = WasmF64.div
163
+ let (*) = WasmF64.mul
164
+ let (+) = WasmF64.add
165
+ // Constants
166
+ let infinity = 1.0W / 0.0W
167
+ let nan = 0.0W / 0.0W
168
+ let x = coerceNumberToWasmF64(base)
169
+ let y = coerceNumberToWasmF64(power)
170
+ let mut foundOutput = false, output = 0.0W
171
+ // Fast paths
172
+ if (WasmF64.abs(y) <= 2.0W) {
173
+ if (y == 2.0W) {
174
+ foundOutput = true
175
+ output = x * x
176
+ } else if (y == 0.5W) {
177
+ foundOutput = true
178
+ if (x != infinity) output = WasmF64.abs(WasmF64.sqrt(x))
179
+ else output = infinity
180
+ } else if (y == -1.0W) {
181
+ foundOutput = true
182
+ output = 1.0W / x
183
+ } else if (y == 1.0W) {
184
+ foundOutput = true
185
+ output = x
186
+ } else if (y == 0.0W) {
187
+ foundOutput = true
188
+ output = nan
189
+ }
190
+ }
191
+ // Full calculation
192
+ if (foundOutput) {
193
+ WasmI32.toGrain(newFloat64(output)): Number
194
+ } else {
195
+ let dp_h1 = WasmF64.reinterpretI64(0x3FE2B80340000000N)
196
+ let dp_l1 = WasmF64.reinterpretI64(0x3E4CFDEB43CFD006N)
197
+ let two53 = WasmF64.reinterpretI64(0x4340000000000000N)
198
+ let huge = WasmF64.reinterpretI64(0x7E37E43C8800759CN)
199
+ let tiny = WasmF64.reinterpretI64(0x01A56E1FC2F8F359N)
200
+ let l1 = WasmF64.reinterpretI64(0x3FE3333333333303N)
201
+ let l2 = WasmF64.reinterpretI64(0x3FDB6DB6DB6FABFFN)
202
+ let l3 = WasmF64.reinterpretI64(0x3FD55555518F264DN)
203
+ let l4 = WasmF64.reinterpretI64(0x3FD17460A91D4101N)
204
+ let l5 = WasmF64.reinterpretI64(0x3FCD864A93C9DB65N)
205
+ let l6 = WasmF64.reinterpretI64(0x3FCA7E284A454EEFN)
206
+ let p1 = WasmF64.reinterpretI64(0x3FC555555555553EN)
207
+ let p2 = WasmF64.reinterpretI64(0xBF66C16C16BEBD93N)
208
+ let p3 = WasmF64.reinterpretI64(0x3F11566AAF25DE2CN)
209
+ let p4 = WasmF64.reinterpretI64(0xBEBBBD41C5D26BF1N)
210
+ let p5 = WasmF64.reinterpretI64(0x3E66376972BEA4D0N)
211
+ let lg2 = WasmF64.reinterpretI64(0x3FE62E42FEFA39EFN)
212
+ let lg2_h = WasmF64.reinterpretI64(0x3FE62E4300000000N)
213
+ let lg2_l = WasmF64.reinterpretI64(0xBE205C610CA86C39N)
214
+ let ovt = WasmF64.reinterpretI64(0x3C971547652B82FEN)
215
+ let cp = WasmF64.reinterpretI64(0x3FEEC709DC3A03FDN)
216
+ let cp_h = WasmF64.reinterpretI64(0x3FEEC709E0000000N)
217
+ let cp_l = WasmF64.reinterpretI64(0xBE3E2FE0145B01F5N)
218
+ let ivln2 = WasmF64.reinterpretI64(0x3FF71547652B82FEN)
219
+ let ivln2_h = WasmF64.reinterpretI64(0x3FF7154760000000N)
220
+ let ivln2_l = WasmF64.reinterpretI64(0x3E54AE0BF85DDF44N)
221
+ let inv3 = WasmF64.reinterpretI64(0x3FD5555555555555N)
222
+ let (==) = WasmI32.eq
223
+ let (!=) = WasmI32.ne
224
+ let (>=) = WasmI32.geS
225
+ let (<=) = WasmI32.leS
226
+ let (&) = WasmI32.and
227
+ let (|) = WasmI32.or
228
+ let (>) = WasmI32.gtS
229
+ let (<) = WasmI32.ltS
230
+ let (<<) = WasmI32.shl
231
+ let (>>) = WasmI32.shrS
232
+ let (-) = WasmI32.sub
233
+ let (+) = WasmI32.add
234
+ let u_ = WasmI64.reinterpretF64(x)
235
+ let hx = WasmI32.wrapI64(WasmI64.shrS(u_, 32N))
236
+ let lx = WasmI32.wrapI64(u_)
237
+ let u_ = WasmI64.reinterpretF64(y)
238
+ let hy = WasmI32.wrapI64(WasmI64.shrS(u_, 32N))
239
+ let ly = WasmI32.wrapI64(u_)
240
+ let mut ix = hx & 0x7FFFFFFFn
241
+ let iy = hy & 0x7FFFFFFFn
242
+ if ((iy | ly) == 0n) { // x**0 = 1, even if x is NaN
243
+ 1 // return 1
244
+ } else if (
245
+ // Either Argument is Nan
246
+ ix > 0x7FF00000n ||
247
+ ix == 0x7FF00000n && lx != 0n ||
248
+ iy > 0x7FF00000n ||
249
+ iy == 0x7FF00000n && ly != 0n
250
+ ) {
251
+ WasmI32.toGrain(newFloat64(WasmF64.add(x, y))): Number
252
+ } else {
253
+ let mut yisint = 0n
254
+ let mut k = 0n
255
+ if (hx < 0n) {
256
+ if (iy >= 0x43400000n) {
257
+ yisint = 2n
258
+ } else if (iy >= 0x3FF00000n) {
259
+ k = (iy >> 20n) - 0x3FFn
260
+ let mut offset = 0n
261
+ let mut _ly = 0n
262
+ if (k > 20n) {
263
+ offset = 52n - k
264
+ _ly = ly
265
+ } else {
266
+ offset = 20n - k
267
+ _ly = iy
268
+ }
269
+ let jj = _ly >> offset
270
+ if (jj << offset == _ly) yisint = 2n - (jj & 1n)
271
+ }
272
+ }
273
+ if (ly == 0n) {
274
+ if (iy == 0x7FF00000n) { // y is +- inf
275
+ foundOutput = true
276
+ if ((ix - 0x3FF00000n | lx) == 0n) { // C: (-1)**+-inf is 1, JS: NaN
277
+ output = nan
278
+ } else if (ix >= 0x3FF00000n) { // (|x|>1)**+-inf = inf,0
279
+ if (hy >= 0n) output = y else output = 0.0W
280
+ } else { // (|x|<1)**+-inf = 0,inf
281
+ if (hy >= 0n) output = 0.0W else output = y * -1.0W
282
+ }
283
+ } else if (iy == 0x3FF00000n) {
284
+ foundOutput = true
285
+ if (hy >= 0n) output = x else output = 1.0W / x
286
+ } else if (hy == 0x3FE00000n) {
287
+ foundOutput = true
288
+ output = x * x
289
+ } else if (hy == 0x3FE00000n) {
290
+ if (hx >= 0n) {
291
+ foundOutput = true
292
+ output = WasmF64.sqrt(x)
293
+ }
294
+ }
295
+ }
296
+ if (foundOutput) {
297
+ WasmI32.toGrain(newFloat64(output)): Number
298
+ } else {
299
+ let mut ax = WasmF64.abs(x)
300
+ let mut z = 0.0W
301
+ if (
302
+ lx == 0n && (ix == 0n || ix == 0x7FF00000n || ix == 0x3FF00000n)
303
+ ) {
304
+ z = ax
305
+ if (hy < 0n) z = 1.0W / z
306
+ if (hx < 0n) {
307
+ if ((ix - 0x3FF00000n | yisint) == 0n) {
308
+ let d = WasmF64.sub(z, z)
309
+ z = d / d
310
+ } else if (yisint == 1n) z *= -1.0W
311
+ }
312
+ WasmI32.toGrain(newFloat64(z)): Number
313
+ } else {
314
+ let mut s = 1.0W
315
+ if (hx < 0n) {
316
+ if (yisint == 0n) {
317
+ let d = WasmF64.sub(x, x)
318
+ foundOutput = true
319
+ output = d / d
320
+ } else if (yisint == 1n) s = -1.0W
321
+ }
322
+ if (foundOutput) {
323
+ WasmI32.toGrain(newFloat64(output)): Number
324
+ } else {
325
+ let mut t1 = 0.0W,
326
+ t2 = 0.0W,
327
+ p_h = 0.0W,
328
+ p_l = 0.0W,
329
+ r = 0.0W,
330
+ t = 0.0W,
331
+ u = 0.0W,
332
+ v = 0.0W,
333
+ w = 0.0W
334
+ let mut j = 0n, n = 0n
335
+ if (iy > 0x41E00000n) {
336
+ if (iy > 0x43F00000n) {
337
+ if (ix <= 0x3FEFFFFFn) {
338
+ foundOutput = true
339
+ if (hy < 0n) output = huge * huge else output = tiny * tiny
340
+ } else if (ix >= 0x3FF00000n) {
341
+ foundOutput = true
342
+ if (hy > 0n) output = huge * huge else output = tiny * tiny
343
+ }
344
+ }
345
+ if (!foundOutput) {
346
+ if (ix < 0x3FEFFFFFn) {
347
+ foundOutput = true
348
+ if (hy < 0n) {
349
+ output = s * huge * huge
350
+ } else {
351
+ output = s * tiny * tiny
352
+ }
353
+ } else if (ix > 0x3FF00000n) {
354
+ foundOutput = true
355
+ if (hy > 0n) {
356
+ output = s * huge * huge
357
+ } else {
358
+ output = s * tiny * tiny
359
+ }
360
+ } else {
361
+ let (-) = WasmF64.sub
362
+ let (&) = WasmI64.and
363
+ t = ax - 1.0W
364
+ w = t * t * (0.5W - t * (inv3 - t * 0.25W))
365
+ u = ivln2_h * t
366
+ v = t * ivln2_l - w * ivln2
367
+ t1 = WasmF64.add(u, v)
368
+ t1 = WasmF64.reinterpretI64(
369
+ WasmI64.reinterpretF64(t1) & 0xFFFFFFFF00000000N
370
+ )
371
+ t2 = v - (t1 - u)
372
+ }
373
+ }
374
+ } else {
375
+ let mut ss = 0.0W,
376
+ s2 = 0.0W,
377
+ s_h = 0.0W,
378
+ s_l = 0.0W,
379
+ t_h = 0.0W,
380
+ t_l = 0.0W
381
+ n = 0n
382
+ if (ix < 0x00100000n) {
383
+ let (>>) = WasmI64.shrU
384
+ ax *= two53
385
+ n -= 53n
386
+ ix = WasmI32.wrapI64(WasmI64.reinterpretF64(ax) >> 32N)
387
+ }
388
+ n += (ix >> 20n) - 0x3FFn
389
+ j = ix & 0x000FFFFFn
390
+ ix = j | 0x3FF00000n
391
+ if (j <= 0x3988En) {
392
+ k = 0n
393
+ } else if (j < 0xBB67An) {
394
+ k = 1n
395
+ } else {
396
+ k = 0n
397
+ n += 1n
398
+ ix -= 0x00100000n
399
+ }
400
+ let (&) = WasmI64.and
401
+ let (|) = WasmI64.or
402
+ let (<<) = WasmI64.shl
403
+ ax = WasmF64.reinterpretI64(
404
+ WasmI64.reinterpretF64(ax) & 0xFFFFFFFFN |
405
+ WasmI64.extendI32S(ix) << 32N
406
+ )
407
+ let bp = if (k != 0n) 1.5W else 1.0W
408
+ u = WasmF64.sub(ax, bp)
409
+ v = 1.0W / WasmF64.add(ax, bp)
410
+ ss = u * v
411
+ s_h = ss
412
+ s_h = WasmF64.reinterpretI64(
413
+ WasmI64.reinterpretF64(s_h) & 0xFFFFFFFF00000000N
414
+ )
415
+ t_h = WasmF64.reinterpretI64(
416
+ WasmI64.shl(
417
+ WasmI64.extendI32S(
418
+ WasmI32.or(WasmI32.shrS(ix, 1n), 0x20000000n) +
419
+ 0x00080000n +
420
+ WasmI32.shl(k, 18n)
421
+ ),
422
+ 32N
423
+ )
424
+ )
425
+ let (-) = WasmF64.sub
426
+ let (+) = WasmF64.add
427
+ t_l = ax - (t_h - bp)
428
+ s_l = v * (u - s_h * t_h - s_h * t_l)
429
+ s2 = ss * ss
430
+ //formatter-ignore
431
+ r = s2 * s2 * (l1 + s2 * (l2 + s2 * (l3 + s2 * (l4 + s2 * (l5 + s2 * l6)))))
432
+ r += s_l * (s_h + ss)
433
+ s2 = s_h * s_h
434
+ t_h = 3.0W + s2 + r
435
+ t_h = WasmF64.reinterpretI64(
436
+ WasmI64.reinterpretF64(t_h) & 0xFFFFFFFF00000000N
437
+ )
438
+ t_l = r - (t_h - 3.0W - s2)
439
+ u = s_h * t_h
440
+ v = s_l * t_h + t_l * ss
441
+ p_h = u + v
442
+ p_h = WasmF64.reinterpretI64(
443
+ WasmI64.reinterpretF64(p_h) & 0xFFFFFFFF00000000N
444
+ )
445
+ p_l = v - (p_h - u)
446
+ let z_h = cp_h * p_h
447
+ let dp_l = if (k != 0n) dp_l1 else 0.0W
448
+ let z_l = cp_l * p_h + p_l * cp + dp_l
449
+ t = WasmF64.convertI32S(n)
450
+ let dp_h = if (k != 0n) dp_h1 else 0.0W
451
+ t1 = z_h + z_l + dp_h + t
452
+ t1 = WasmF64.reinterpretI64(
453
+ WasmI64.reinterpretF64(t1) & 0xFFFFFFFF00000000N
454
+ )
455
+ t2 = z_l - (t1 - t - dp_h - z_h)
456
+ }
457
+ if (foundOutput) {
458
+ WasmI32.toGrain(newFloat64(output)): Number
459
+ } else {
460
+ let (>) = WasmF64.gt
461
+ let (&) = WasmI64.and
462
+ let (-) = WasmF64.sub
463
+ let (+) = WasmF64.add
464
+ let (>>) = WasmI64.shrS
465
+ let y1 = WasmF64.reinterpretI64(
466
+ WasmI64.reinterpretF64(y) & 0xFFFFFFFF00000000N
467
+ )
468
+ p_l = (y - y1) * t1 + y * t2
469
+ p_h = y1 * t1
470
+ z = p_l + p_h
471
+ let u_ = WasmI64.reinterpretF64(z)
472
+ let j = WasmI32.wrapI64(u_ >> 32N)
473
+ let i = WasmI32.wrapI64(u_)
474
+ if (j >= 0x40900000n) {
475
+ if ((WasmI32.sub(j, 0x40900000n) | i) != 0n) {
476
+ foundOutput = true
477
+ output = s * huge * huge
478
+ } else if (p_l + ovt > z - p_h) {
479
+ foundOutput = true
480
+ output = s * huge * huge
481
+ }
482
+ } else if (WasmI32.and(j, 0x7FFFFFFFn) >= 0x4090CC00n) {
483
+ if (WasmI32.sub(j, 0xC090CC00n | i) != 0n) {
484
+ foundOutput = true
485
+ output = s * tiny * tiny
486
+ } else if (WasmF64.le(p_l, z - p_h)) {
487
+ foundOutput = true
488
+ output = s * tiny * tiny
489
+ }
490
+ }
491
+ if (foundOutput) {
492
+ WasmI32.toGrain(newFloat64(output)): Number
493
+ } else {
494
+ let (&) = WasmI32.and
495
+ let (>>) = WasmI32.shrS
496
+ let (-) = WasmI32.sub
497
+ let (+) = WasmI32.add
498
+ let (>) = WasmI32.gtS
499
+ let (*) = WasmI32.mul
500
+ let i = j & 0x7FFFFFFFn
501
+ k = (i >> 20n) - 0x3FFn
502
+ n = 0n
503
+ if (i > 0x3FE00000n) {
504
+ n = j + (0x00100000n >> k + 1n)
505
+ k = ((n & 0x7FFFFFFFn) >> 20n) - 0x3FFn
506
+ t = 0.0W
507
+ t = WasmF64.reinterpretI64(
508
+ WasmI64.shl(
509
+ WasmI64.extendI32S(
510
+ n & WasmI32.xor(0x000FFFFFn >> k, -1n)
511
+ ),
512
+ 32N
513
+ )
514
+ )
515
+ n = (n & 0x000FFFFFn | 0x00100000n) >> 20n - k
516
+ if (j < 0n) n *= -1n
517
+ p_h = WasmF64.sub(p_h, t)
518
+ }
519
+ let (&) = WasmI64.and
520
+ let (|) = WasmI64.or
521
+ let (*) = WasmF64.mul
522
+ let (-) = WasmF64.sub
523
+ let (+) = WasmF64.add
524
+ t = WasmF64.add(p_l, p_h)
525
+ t = WasmF64.reinterpretI64(
526
+ WasmI64.reinterpretF64(t) & 0xFFFFFFFF00000000N
527
+ )
528
+ u = t * lg2_h
529
+ v = (p_l - (t - p_h)) * lg2 + t * lg2_l
530
+ z = u + v
531
+ w = v - (z - u)
532
+ t = z * z
533
+ t1 = z - t * (p1 + t * (p2 + t * (p3 + t * (p4 + t * p5))))
534
+ r = z * t1 / (t1 - 2.0W) - (w + z * w)
535
+ z = 1.0W - (r - z)
536
+ let j = WasmI32.add(
537
+ WasmI32.wrapI64(
538
+ WasmI64.shrS(WasmI64.reinterpretF64(z), 32N)
539
+ ),
540
+ WasmI32.shl(n, 20n)
541
+ )
542
+ if (WasmI32.shrS(j, 20n) <= 0n) {
543
+ z = scalbn(z, n)
544
+ } else {
545
+ z = WasmF64.reinterpretI64(
546
+ WasmI64.reinterpretF64(z) & 0xFFFFFFFFN |
547
+ WasmI64.shl(WasmI64.extendI32S(j), 32N)
548
+ )
549
+ }
550
+ WasmI32.toGrain(newFloat64(s * z)): Number
551
+ }
552
+ }
553
+ }
554
+ }
555
+ }
556
+ }
557
+ }
558
+ }
559
+ }
560
+
561
+ /**
562
+ * Computes the exponentiation of Euler's number to the given power.
563
+ *
564
+ * @param power: The exponent number
565
+ * @returns The `Number.e` value raised to the given power
566
+ *
567
+ * @since v0.5.4
568
+ */
569
+ export let exp = power => {
570
+ if (power == 0) 1 else pow(e, power)
571
+ }
97
572
  /**
98
573
  * Computes the square root of its operand.
99
574
  *
@@ -140,8 +615,9 @@ export let sign = x => {
140
615
  * @returns The smaller of the two operands
141
616
  *
142
617
  * @since v0.4.0
618
+ * @history v0.5.4: Handle NaN properly
143
619
  */
144
- export let min = (x: Number, y: Number) => if (y > x) x else y
620
+ export let min = (x: Number, y: Number) => if (compare(x, y) < 0) x else y
145
621
 
146
622
  /**
147
623
  * Returns the larger of its operands.
@@ -151,8 +627,9 @@ export let min = (x: Number, y: Number) => if (y > x) x else y
151
627
  * @returns The larger of the two operands
152
628
  *
153
629
  * @since v0.4.0
630
+ * @history v0.5.4: Handle NaN properly
154
631
  */
155
- export let max = (x: Number, y: Number) => if (x > y) x else y
632
+ export let max = (x: Number, y: Number) => if (compare(x, y) > 0) x else y
156
633
 
157
634
  /**
158
635
  * Rounds its operand up to the next largest integer.
@@ -161,12 +638,19 @@ export let max = (x: Number, y: Number) => if (x > y) x else y
161
638
  * @returns The next largest integer of the operand
162
639
  *
163
640
  * @since v0.4.0
641
+ * @history v0.5.4: Handle NaN and Infinity properly
164
642
  */
165
643
  @unsafe
166
644
  export let ceil = (x: Number) => {
167
- let xval = coerceNumberToWasmF64(x)
168
- let ceiling = WasmI64.truncF64S(WasmF64.ceil(xval))
169
- WasmI32.toGrain(reducedInteger(ceiling)): Number
645
+ if (x != x) {
646
+ nan
647
+ } else if (x == infinity) {
648
+ infinity
649
+ } else {
650
+ let xval = coerceNumberToWasmF64(x)
651
+ let ceiling = WasmI64.truncF64S(WasmF64.ceil(xval))
652
+ WasmI32.toGrain(reducedInteger(ceiling)): Number
653
+ }
170
654
  }
171
655
 
172
656
  /**
@@ -176,12 +660,19 @@ export let ceil = (x: Number) => {
176
660
  * @returns The previous integer of the operand
177
661
  *
178
662
  * @since v0.4.0
663
+ * @history v0.5.4: Handle NaN and Infinity properly
179
664
  */
180
665
  @unsafe
181
666
  export let floor = (x: Number) => {
182
- let xval = coerceNumberToWasmF64(x)
183
- let floored = WasmI64.truncF64S(WasmF64.floor(xval))
184
- WasmI32.toGrain(reducedInteger(floored)): Number
667
+ if (x != x) {
668
+ nan
669
+ } else if (x == infinity) {
670
+ infinity
671
+ } else {
672
+ let xval = coerceNumberToWasmF64(x)
673
+ let floored = WasmI64.truncF64S(WasmF64.floor(xval))
674
+ WasmI32.toGrain(reducedInteger(floored)): Number
675
+ }
185
676
  }
186
677
 
187
678
  /**
@@ -191,12 +682,19 @@ export let floor = (x: Number) => {
191
682
  * @returns The integer part of the operand
192
683
  *
193
684
  * @since v0.4.0
685
+ * @history v0.5.4: Handle NaN and Infinity properly
194
686
  */
195
687
  @unsafe
196
688
  export let trunc = (x: Number) => {
197
- let xval = coerceNumberToWasmF64(x)
198
- let trunced = WasmI64.truncF64S(xval)
199
- WasmI32.toGrain(reducedInteger(trunced)): Number
689
+ if (x != x) {
690
+ nan
691
+ } else if (x == infinity) {
692
+ infinity
693
+ } else {
694
+ let xval = coerceNumberToWasmF64(x)
695
+ let trunced = WasmI64.truncF64S(xval)
696
+ WasmI32.toGrain(reducedInteger(trunced)): Number
697
+ }
200
698
  }
201
699
 
202
700
  /**
@@ -206,12 +704,19 @@ export let trunc = (x: Number) => {
206
704
  * @returns The nearest integer to the operand
207
705
  *
208
706
  * @since v0.4.0
707
+ * @history v0.5.4: Handle NaN and Infinity properly
209
708
  */
210
709
  @unsafe
211
710
  export let round = (x: Number) => {
212
- let xval = coerceNumberToWasmF64(x)
213
- let rounded = WasmI64.truncF64S(WasmF64.nearest(xval))
214
- WasmI32.toGrain(reducedInteger(rounded)): Number
711
+ if (x != x) {
712
+ nan
713
+ } else if (x == infinity) {
714
+ infinity
715
+ } else {
716
+ let xval = coerceNumberToWasmF64(x)
717
+ let rounded = WasmI64.truncF64S(WasmF64.nearest(xval))
718
+ WasmI32.toGrain(reducedInteger(rounded)): Number
719
+ }
215
720
  }
216
721
 
217
722
  /**
@@ -386,7 +891,80 @@ export let isInfinite = (x: Number) => {
386
891
  *
387
892
  * @since v0.4.5
388
893
  */
389
- export parseInt
894
+ export let parseInt = Atoi.parseInt
895
+
896
+ /**
897
+ * Parses a string representation of a float into a `Number`. Underscores that appear
898
+ * in numeric portions of the input are ignored.
899
+ *
900
+ * @param input: The string to parse
901
+ * @returns `Ok(value)` containing the parsed number on a successful parse or `Err(msg)` containing an error message string otherwise
902
+ *
903
+ * @since v0.5.5
904
+ */
905
+ export let parseFloat = Atof.parseFloat
906
+
907
+ /**
908
+ * Parses a string representation of an integer, float, or rational into a `Number`.
909
+ * Underscores that appear in the numeric portion of the input are ignored.
910
+ *
911
+ * @param input: The string to parse
912
+ * @returns `Ok(value)` containing the parsed number on a successful parse or `Err(msg)` containing an error message string otherwise
913
+ *
914
+ * @since v0.5.5
915
+ */
916
+ @unsafe
917
+ export let parse = input => {
918
+ match (parseInt(input, 10)) {
919
+ Ok(number) => Ok(number),
920
+ Err(msg) =>
921
+ match (parseFloat(input)) {
922
+ Ok(number) => Ok(number),
923
+ Err(_) => {
924
+ // Split the input on a `/` and attempt to parse a rational
925
+ let (+) = WasmI32.add
926
+ let (-) = WasmI32.sub
927
+ let (<) = WasmI32.ltU
928
+ let (==) = WasmI32.eq
929
+
930
+ // Search for `/`
931
+ let input = WasmI32.fromGrain(input)
932
+ let len = WasmI32.load(input, 4n)
933
+ let mut slashIdx = -1n
934
+ for (let mut i = 0n; i < len; i += 1n) {
935
+ if (WasmI32.load8U(input + i, 8n) == 0x2fn) {
936
+ slashIdx = i
937
+ break
938
+ }
939
+ }
940
+
941
+ if (slashIdx == -1n) {
942
+ Err(msg)
943
+ } else {
944
+ let numeratorLen = slashIdx
945
+ let denominatorLen = len - slashIdx - 1n
946
+
947
+ let numerator = allocateString(numeratorLen)
948
+ Memory.copy(numerator + 8n, input + 8n, numeratorLen)
949
+ let numerator = WasmI32.toGrain(numerator): String
950
+
951
+ let denominator = allocateString(denominatorLen)
952
+ Memory.copy(
953
+ denominator + 8n,
954
+ input + 8n + slashIdx + 1n,
955
+ denominatorLen
956
+ )
957
+ let denominator = WasmI32.toGrain(denominator): String
958
+
959
+ match ((parseInt(numerator, 10), parseInt(denominator, 10))) {
960
+ (Ok(numerator), Ok(denominator)) => Ok(numerator / denominator),
961
+ (Err(msg), _) | (_, Err(msg)) => Err(msg),
962
+ }
963
+ }
964
+ },
965
+ },
966
+ }
967
+ }
390
968
 
391
969
  /**
392
970
  * Computes how many times pi has to be subtracted to achieve the required bounds for sin.
@@ -417,14 +995,19 @@ let chebyshevSine = (radians: Number) => {
417
995
  * @returns The computed sine
418
996
  *
419
997
  * @since v0.5.2
998
+ * @history v0.5.4: Handle NaN and Infinity
420
999
  */
421
1000
  export let sin = (radians: Number) => {
422
- let quot = reduceToPiBound(radians)
423
- let bounded = radians - pi * quot
424
- if (quot % 2 == 0) {
425
- chebyshevSine(bounded)
1001
+ if (radians != radians || radians == infinity) {
1002
+ nan
426
1003
  } else {
427
- neg(chebyshevSine(bounded))
1004
+ let quot = reduceToPiBound(radians)
1005
+ let bounded = radians - pi * quot
1006
+ if (quot % 2 == 0) {
1007
+ chebyshevSine(bounded)
1008
+ } else {
1009
+ neg(chebyshevSine(bounded))
1010
+ }
428
1011
  }
429
1012
  }
430
1013
 
@@ -435,7 +1018,125 @@ export let sin = (radians: Number) => {
435
1018
  * @returns The computed cosine
436
1019
  *
437
1020
  * @since v0.5.2
1021
+ * @history v0.5.4: Handle NaN and Infinity
438
1022
  */
439
1023
  export let cos = (radians: Number) => {
440
- sin(pi / 2 + radians)
1024
+ if (radians != radians || radians == infinity) {
1025
+ nan
1026
+ } else {
1027
+ sin(pi / 2 + radians)
1028
+ }
1029
+ }
1030
+
1031
+ /**
1032
+ * Computes the tangent of a number (in radians) using Chebyshev polynomials.
1033
+ *
1034
+ * @param radians: The input in radians
1035
+ * @returns The computed tangent
1036
+ *
1037
+ * @since v0.5.4
1038
+ */
1039
+ export let tan = (radians: Number) => {
1040
+ if (isNaN(radians) || isInfinite(radians)) {
1041
+ nan
1042
+ } else {
1043
+ sin(radians) / cos(radians)
1044
+ }
1045
+ }
1046
+
1047
+ // Math.gamma implemented using the Lanczos approximation
1048
+ // https://en.wikipedia.org/wiki/Lanczos_approximation
1049
+ /**
1050
+ * Computes the gamma function of a value using Lanczos approximation.
1051
+ *
1052
+ * @param z: The value to interpolate
1053
+ * @returns The gamma of the given value
1054
+ *
1055
+ * @throws InvalidArgument(String): When `z` is zero
1056
+ *
1057
+ * @since v0.5.4
1058
+ */
1059
+ export let rec gamma = z => {
1060
+ if (z == 0) {
1061
+ throw Exception.InvalidArgument("Gamma of 0 is undefined")
1062
+ } else if (isInteger(z) && z > 0) {
1063
+ let mut output = 1
1064
+ for (let mut i = 1; i < z; i += 1) {
1065
+ output *= i
1066
+ }
1067
+ output
1068
+ } else {
1069
+ let mut z = z
1070
+ let g = 7
1071
+ let c = [>
1072
+ 0.99999999999980993,
1073
+ 676.5203681218851,
1074
+ -1259.1392167224028,
1075
+ 771.32342877765313,
1076
+ -176.61502916214059,
1077
+ 12.507343278686905,
1078
+ -0.13857109526572012,
1079
+ 9.9843695780195716e-6,
1080
+ 1.5056327351493116e-7,
1081
+ ]
1082
+ let mut output = 0
1083
+ if (z < 0.5) {
1084
+ output = pi / (sin(pi * z) * gamma(1 - z))
1085
+ } else if (z == 0.5) {
1086
+ // Handle this case separately because it is out of the domain of Number.pow when calculating
1087
+ output = 1.7724538509055159
1088
+ } else {
1089
+ z -= 1
1090
+ let mut x = c[0]
1091
+ for (let mut i = 1; i < g + 2; i += 1) {
1092
+ x += c[i] / (z + i)
1093
+ }
1094
+
1095
+ let t = z + g + 0.5
1096
+ output = sqrt(2 * pi) * pow(t, z + 0.5) * exp(t * -1) * x
1097
+ }
1098
+ if (abs(output) == infinity) infinity else output
1099
+ }
1100
+ }
1101
+
1102
+ /**
1103
+ * Computes the product of consecutive integers for an integer input and computes the gamma function for non-integer inputs.
1104
+ *
1105
+ * @param n: The value to factorialize
1106
+ * @returns The factorial of the given value
1107
+ *
1108
+ * @throws InvalidArgument(String): When `n` is negative
1109
+ *
1110
+ * @since v0.5.4
1111
+ */
1112
+ export let rec factorial = n => {
1113
+ if (isInteger(n) && n < 0) gamma(abs(n) + 1) * -1 else if (
1114
+ !isInteger(n) && n < 0
1115
+ ) {
1116
+ throw Exception.InvalidArgument(
1117
+ "Cannot compute the factorial of a negative non-integer"
1118
+ )
1119
+ } else {
1120
+ gamma(n + 1)
1121
+ }
441
1122
  }
1123
+
1124
+ /**
1125
+ * Converts degrees to radians.
1126
+ *
1127
+ * @param degrees: The value to convert
1128
+ * @returns The value in radians
1129
+ *
1130
+ * @since v0.5.4
1131
+ */
1132
+ export let toRadians = degrees => degrees * (pi / 180)
1133
+
1134
+ /**
1135
+ * Converts radians to degrees.
1136
+ *
1137
+ * @param radians: The value to convert
1138
+ * @returns The value in degrees
1139
+ *
1140
+ * @since v0.5.4
1141
+ */
1142
+ export let toDegrees = radians => radians * (180 / pi)