jz 0.0.0 → 0.1.1
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/LICENSE +21 -0
- package/README.md +373 -0
- package/cli.js +163 -0
- package/index.js +247 -0
- package/module/array.js +1322 -0
- package/module/collection.js +793 -0
- package/module/console.js +192 -0
- package/module/core.js +644 -0
- package/module/function.js +181 -0
- package/module/index.js +15 -0
- package/module/json.js +506 -0
- package/module/math.js +390 -0
- package/module/number.js +601 -0
- package/module/object.js +359 -0
- package/module/regex.js +914 -0
- package/module/schema.js +106 -0
- package/module/string.js +985 -0
- package/module/symbol.js +55 -0
- package/module/timer.js +253 -0
- package/module/typedarray.js +713 -0
- package/package.json +56 -5
- package/src/analyze.js +1927 -0
- package/src/autoload.js +175 -0
- package/src/compile.js +1211 -0
- package/src/ctx.js +244 -0
- package/src/emit.js +2105 -0
- package/src/host.js +536 -0
- package/src/ir.js +649 -0
- package/src/jzify.js +418 -0
- package/src/key.js +73 -0
- package/src/narrow.js +928 -0
- package/src/optimize.js +1352 -0
- package/src/plan.js +105 -0
- package/src/prepare.js +1534 -0
- package/src/source.js +76 -0
- package/wasi.js +80 -0
package/module/math.js
ADDED
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Math module - Math.sin, Math.cos, Math.sqrt, Math.PI, etc.
|
|
3
|
+
*
|
|
4
|
+
* Module API:
|
|
5
|
+
* - ctx.core.emit['math.X'] = (args) => WasmNode - custom emitters
|
|
6
|
+
* - ctx.core.stdlib['math.X'] = '(func ...)' - WAT function definitions
|
|
7
|
+
* - ctx.deps['math.X'] = ['dep1', 'dep2'] - stdlib dependencies
|
|
8
|
+
* - include('math.X') - marks stdlib for inclusion (called by emitters)
|
|
9
|
+
*
|
|
10
|
+
* Prepare resolves Math.sin(x) → ['()', 'math.sin', x]
|
|
11
|
+
* Compile looks up ctx.core.emit['math.sin'] and calls it.
|
|
12
|
+
*
|
|
13
|
+
* @module math
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { typed, asF64, asI32, temp, arrayLoop } from '../src/ir.js'
|
|
17
|
+
import { emit } from '../src/emit.js'
|
|
18
|
+
import { inc } from '../src/ctx.js'
|
|
19
|
+
import { repOf } from '../src/analyze.js'
|
|
20
|
+
|
|
21
|
+
export default (ctx) => {
|
|
22
|
+
// Helpers: all math ops take f64 and return f64
|
|
23
|
+
const f = (op, a) => typed([op, asF64(emit(a))], 'f64')
|
|
24
|
+
const f2 = (op, a, b) => typed([op, asF64(emit(a)), asF64(emit(b))], 'f64')
|
|
25
|
+
// floor/ceil/trunc/round are no-ops on integer-valued operands. When the
|
|
26
|
+
// arg is a local whose every def is integer-valued (intCertain lattice),
|
|
27
|
+
// skip the wasm op and just hand back the operand cast to f64.
|
|
28
|
+
const fInt = (op, a) => typeof a === 'string' && repOf(a)?.intCertain === true
|
|
29
|
+
? asF64(emit(a))
|
|
30
|
+
: f(op, a)
|
|
31
|
+
const call = (name, ...args) => (inc(name), typed(['call', `$${name}`, ...args.map(a => asF64(emit(a)))], 'f64'))
|
|
32
|
+
const callDeps = (deps, name, ...args) => (inc(...deps), call(name, ...args))
|
|
33
|
+
|
|
34
|
+
// Constants
|
|
35
|
+
ctx.core.emit['math.PI'] = () => typed(['f64.const', Math.PI], 'f64')
|
|
36
|
+
ctx.core.emit['math.E'] = () => typed(['f64.const', Math.E], 'f64')
|
|
37
|
+
ctx.core.emit['math.LN2'] = () => typed(['f64.const', Math.LN2], 'f64')
|
|
38
|
+
ctx.core.emit['math.LN10'] = () => typed(['f64.const', Math.LN10], 'f64')
|
|
39
|
+
ctx.core.emit['math.LOG2E'] = () => typed(['f64.const', Math.LOG2E], 'f64')
|
|
40
|
+
ctx.core.emit['math.LOG10E'] = () => typed(['f64.const', Math.LOG10E], 'f64')
|
|
41
|
+
ctx.core.emit['math.SQRT2'] = () => typed(['f64.const', Math.SQRT2], 'f64')
|
|
42
|
+
ctx.core.emit['math.SQRT1_2'] = () => typed(['f64.const', Math.SQRT1_2], 'f64')
|
|
43
|
+
|
|
44
|
+
/** Emit array reduce with a WASM binary op (for Math.max(...arr), Math.min(...arr)) */
|
|
45
|
+
function emitArrayReduce(wasmOp, arrExpr, initVal) {
|
|
46
|
+
const acc = temp('mr')
|
|
47
|
+
const loop = arrayLoop(emit(arrExpr), (_ptr, _len, _i, item) => [
|
|
48
|
+
['local.set', `$${acc}`, [wasmOp, ['local.get', `$${acc}`], asF64(item)]]
|
|
49
|
+
])
|
|
50
|
+
return typed(['block', ['result', 'f64'],
|
|
51
|
+
['local.set', `$${acc}`, ['f64.const', initVal]],
|
|
52
|
+
...loop,
|
|
53
|
+
['local.get', `$${acc}`]], 'f64')
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Built-in WASM ops
|
|
57
|
+
ctx.core.emit['math.sqrt'] = a => f('f64.sqrt', a)
|
|
58
|
+
ctx.core.emit['math.abs'] = a => f('f64.abs', a)
|
|
59
|
+
ctx.core.emit['math.floor'] = a => fInt('f64.floor', a)
|
|
60
|
+
ctx.core.emit['math.ceil'] = a => fInt('f64.ceil', a)
|
|
61
|
+
ctx.core.emit['math.trunc'] = a => fInt('f64.trunc', a)
|
|
62
|
+
ctx.core.emit['math.min'] = (a, b, ...rest) => {
|
|
63
|
+
// Spread: Math.min(...arr) — iterate array to find min
|
|
64
|
+
if (!b && Array.isArray(a) && a[0] === '...') return emitArrayReduce('f64.min', a[1], Infinity)
|
|
65
|
+
return f2('f64.min', a, b)
|
|
66
|
+
}
|
|
67
|
+
ctx.core.emit['math.max'] = (a, b, ...rest) => {
|
|
68
|
+
if (!b && Array.isArray(a) && a[0] === '...') return emitArrayReduce('f64.max', a[1], -Infinity)
|
|
69
|
+
return f2('f64.max', a, b)
|
|
70
|
+
}
|
|
71
|
+
ctx.core.emit['math.round'] = a => fInt('f64.nearest', a)
|
|
72
|
+
ctx.core.emit['math.fround'] = a => typed(['f64.promote_f32', ['f32.demote_f64', asF64(emit(a))]], 'f64')
|
|
73
|
+
|
|
74
|
+
// Sign
|
|
75
|
+
ctx.core.emit['math.sign'] = a => call('math.sign', a)
|
|
76
|
+
|
|
77
|
+
// Trig
|
|
78
|
+
ctx.core.emit['math.sin'] = a => call('math.sin', a)
|
|
79
|
+
ctx.core.emit['math.cos'] = a => call('math.cos', a)
|
|
80
|
+
ctx.core.emit['math.tan'] = a => callDeps(['math.sin', 'math.cos', 'math.tan'], 'math.tan', a)
|
|
81
|
+
|
|
82
|
+
// Inverse trig
|
|
83
|
+
ctx.core.emit['math.asin'] = a => callDeps(['math.atan', 'math.asin'], 'math.asin', a)
|
|
84
|
+
ctx.core.emit['math.acos'] = a => callDeps(['math.atan', 'math.asin', 'math.acos'], 'math.acos', a)
|
|
85
|
+
ctx.core.emit['math.atan'] = a => call('math.atan', a)
|
|
86
|
+
ctx.core.emit['math.atan2'] = (a, b) => callDeps(['math.atan', 'math.atan2'], 'math.atan2', a, b)
|
|
87
|
+
|
|
88
|
+
// Hyperbolic
|
|
89
|
+
ctx.core.emit['math.sinh'] = a => callDeps(['math.exp', 'math.sinh'], 'math.sinh', a)
|
|
90
|
+
ctx.core.emit['math.cosh'] = a => callDeps(['math.exp', 'math.cosh'], 'math.cosh', a)
|
|
91
|
+
ctx.core.emit['math.tanh'] = a => callDeps(['math.exp', 'math.tanh'], 'math.tanh', a)
|
|
92
|
+
|
|
93
|
+
// Inverse hyperbolic
|
|
94
|
+
ctx.core.emit['math.asinh'] = a => callDeps(['math.log', 'math.asinh'], 'math.asinh', a)
|
|
95
|
+
ctx.core.emit['math.acosh'] = a => callDeps(['math.log', 'math.acosh'], 'math.acosh', a)
|
|
96
|
+
ctx.core.emit['math.atanh'] = a => callDeps(['math.log', 'math.atanh'], 'math.atanh', a)
|
|
97
|
+
|
|
98
|
+
// Exponential and logarithmic
|
|
99
|
+
ctx.core.emit['math.exp'] = a => call('math.exp', a)
|
|
100
|
+
ctx.core.emit['math.expm1'] = a => callDeps(['math.exp', 'math.expm1'], 'math.expm1', a)
|
|
101
|
+
ctx.core.emit['math.log'] = a => call('math.log', a)
|
|
102
|
+
ctx.core.emit['math.log2'] = a => callDeps(['math.log', 'math.log2'], 'math.log2', a)
|
|
103
|
+
ctx.core.emit['math.log10'] = a => callDeps(['math.log', 'math.log10'], 'math.log10', a)
|
|
104
|
+
ctx.core.emit['math.log1p'] = a => callDeps(['math.log', 'math.log1p'], 'math.log1p', a)
|
|
105
|
+
|
|
106
|
+
// Power
|
|
107
|
+
ctx.core.emit['math.pow'] = (a, b) => callDeps(['math.exp', 'math.log', 'math.pow'], 'math.pow', a, b)
|
|
108
|
+
ctx.core.emit['**'] = ctx.core.emit['math.pow']
|
|
109
|
+
ctx.core.emit['math.cbrt'] = a => callDeps(['math.exp', 'math.log', 'math.pow', 'math.cbrt'], 'math.cbrt', a)
|
|
110
|
+
ctx.core.emit['math.hypot'] = (a, b) => call('math.hypot', a, b)
|
|
111
|
+
|
|
112
|
+
// Integer/bit operations: return i32 directly. Consumers `asF64`-rebox at
|
|
113
|
+
// store/return boundaries; consumers staying in i32 (bit chains, i32 locals)
|
|
114
|
+
// skip the convert/trunc round-trip entirely.
|
|
115
|
+
ctx.core.emit['math.clz32'] = a => typed(['i32.clz', asI32(emit(a))], 'i32')
|
|
116
|
+
ctx.core.emit['math.imul'] = (a, b) => typed(['i32.mul', asI32(emit(a)), asI32(emit(b))], 'i32')
|
|
117
|
+
|
|
118
|
+
// Random
|
|
119
|
+
ctx.core.emit['math.random'] = () => (inc('math.random'), typed(['call', '$math.random'], 'f64'))
|
|
120
|
+
|
|
121
|
+
// ============================================
|
|
122
|
+
// WAT stdlib implementations
|
|
123
|
+
// ============================================
|
|
124
|
+
|
|
125
|
+
ctx.core.stdlib['math.sign'] = `(func $math.sign (param $x f64) (result f64)
|
|
126
|
+
(if (result f64) (f64.eq (local.get $x) (f64.const 0.0))
|
|
127
|
+
(then (f64.const 0.0))
|
|
128
|
+
(else (if (result f64) (f64.gt (local.get $x) (f64.const 0.0))
|
|
129
|
+
(then (f64.const 1.0))
|
|
130
|
+
(else (f64.const -1.0))))))`
|
|
131
|
+
|
|
132
|
+
ctx.core.stdlib['math.sin'] = `(func $math.sin (param $x f64) (result f64)
|
|
133
|
+
(local $n i32) (local $r f64) (local $x2 f64) (local $sign f64)
|
|
134
|
+
(local.set $sign (f64.const 1.0))
|
|
135
|
+
(local.set $n (i32.trunc_f64_s (f64.floor (f64.div (local.get $x) (f64.const ${Math.PI})))))
|
|
136
|
+
(local.set $r (f64.sub (local.get $x) (f64.mul (f64.convert_i32_s (local.get $n)) (f64.const ${Math.PI}))))
|
|
137
|
+
(if (i32.and (local.get $n) (i32.const 1)) (then (local.set $sign (f64.const -1.0))))
|
|
138
|
+
(if (f64.gt (local.get $r) (f64.const ${Math.PI / 2})) (then (local.set $r (f64.sub (f64.const ${Math.PI}) (local.get $r)))))
|
|
139
|
+
(if (f64.lt (local.get $r) (f64.const 0.0)) (then
|
|
140
|
+
(local.set $r (f64.neg (local.get $r)))
|
|
141
|
+
(local.set $sign (f64.neg (local.get $sign)))))
|
|
142
|
+
(local.set $x2 (f64.mul (local.get $r) (local.get $r)))
|
|
143
|
+
(f64.mul (local.get $sign) (f64.mul (local.get $r) (f64.sub (f64.const 1.0) (f64.mul (local.get $x2)
|
|
144
|
+
(f64.sub (f64.const 0.16666666666666666) (f64.mul (local.get $x2)
|
|
145
|
+
(f64.sub (f64.const 0.008333333333333333) (f64.mul (local.get $x2)
|
|
146
|
+
(f64.sub (f64.const 0.0001984126984126984) (f64.mul (local.get $x2)
|
|
147
|
+
(f64.sub (f64.const 0.0000027557319223985893) (f64.mul (local.get $x2)
|
|
148
|
+
(f64.const 2.505210838544172e-8))))))))))))))`
|
|
149
|
+
|
|
150
|
+
ctx.core.stdlib['math.cos'] = `(func $math.cos (param $x f64) (result f64)
|
|
151
|
+
(local $n i32) (local $r f64) (local $x2 f64) (local $sign f64)
|
|
152
|
+
(local.set $sign (f64.const 1.0))
|
|
153
|
+
(local.set $n (i32.trunc_f64_s (f64.floor (f64.div (local.get $x) (f64.const ${Math.PI})))))
|
|
154
|
+
(local.set $r (f64.sub (local.get $x) (f64.mul (f64.convert_i32_s (local.get $n)) (f64.const ${Math.PI}))))
|
|
155
|
+
(if (i32.and (local.get $n) (i32.const 1)) (then (local.set $sign (f64.const -1.0))))
|
|
156
|
+
(if (f64.gt (local.get $r) (f64.const ${Math.PI / 2})) (then
|
|
157
|
+
(local.set $r (f64.sub (f64.const ${Math.PI}) (local.get $r)))
|
|
158
|
+
(local.set $sign (f64.neg (local.get $sign)))))
|
|
159
|
+
(if (f64.lt (local.get $r) (f64.const 0.0)) (then (local.set $r (f64.neg (local.get $r)))))
|
|
160
|
+
(local.set $x2 (f64.mul (local.get $r) (local.get $r)))
|
|
161
|
+
(f64.mul (local.get $sign) (f64.sub (f64.const 1.0) (f64.mul (local.get $x2)
|
|
162
|
+
(f64.sub (f64.const 0.5) (f64.mul (local.get $x2)
|
|
163
|
+
(f64.sub (f64.const 0.041666666666666664) (f64.mul (local.get $x2)
|
|
164
|
+
(f64.sub (f64.const 0.001388888888888889) (f64.mul (local.get $x2)
|
|
165
|
+
(f64.sub (f64.const 0.0000248015873015873) (f64.mul (local.get $x2)
|
|
166
|
+
(f64.const 2.7557319223985893e-7)))))))))))))`
|
|
167
|
+
|
|
168
|
+
ctx.core.stdlib['math.tan'] = `(func $math.tan (param $x f64) (result f64)
|
|
169
|
+
(f64.div (call $math.sin (local.get $x)) (call $math.cos (local.get $x))))`
|
|
170
|
+
|
|
171
|
+
ctx.core.stdlib['math.exp'] = `(func $math.exp (param $x f64) (result f64)
|
|
172
|
+
(local $k i32) (local $t f64) (local $t2 f64) (local $result f64) (local $pow2 f64)
|
|
173
|
+
(if (result f64) (f64.gt (local.get $x) (f64.const 709.0)) (then (f64.const 1.7976931348623157e+308)) (else
|
|
174
|
+
(if (result f64) (f64.lt (local.get $x) (f64.const -745.0)) (then (f64.const 0.0)) (else
|
|
175
|
+
(local.set $k (i32.trunc_f64_s (f64.div (local.get $x) (f64.const ${Math.LN2}))))
|
|
176
|
+
(local.set $t (f64.sub (local.get $x) (f64.mul (f64.convert_i32_s (local.get $k)) (f64.const ${Math.LN2}))))
|
|
177
|
+
(local.set $t2 (f64.mul (local.get $t) (local.get $t)))
|
|
178
|
+
(local.set $result (f64.add (f64.const 1.0) (f64.add (local.get $t)
|
|
179
|
+
(f64.mul (local.get $t2) (f64.add (f64.const 0.5)
|
|
180
|
+
(f64.mul (local.get $t) (f64.add (f64.const 0.16666666666666666)
|
|
181
|
+
(f64.mul (local.get $t) (f64.add (f64.const 0.041666666666666664)
|
|
182
|
+
(f64.mul (local.get $t) (f64.add (f64.const 0.008333333333333333)
|
|
183
|
+
(f64.mul (local.get $t) (f64.const 0.001388888888888889)))))))))))))
|
|
184
|
+
(local.set $pow2 (f64.const 1.0))
|
|
185
|
+
(if (i32.gt_s (local.get $k) (i32.const 0))
|
|
186
|
+
(then (block $done (loop $loop
|
|
187
|
+
(br_if $done (i32.le_s (local.get $k) (i32.const 0)))
|
|
188
|
+
(local.set $pow2 (f64.mul (local.get $pow2) (f64.const 2.0)))
|
|
189
|
+
(local.set $k (i32.sub (local.get $k) (i32.const 1)))
|
|
190
|
+
(br $loop)))
|
|
191
|
+
(local.set $result (f64.mul (local.get $result) (local.get $pow2))))
|
|
192
|
+
(else (if (i32.lt_s (local.get $k) (i32.const 0))
|
|
193
|
+
(then (block $done2 (loop $loop2
|
|
194
|
+
(br_if $done2 (i32.ge_s (local.get $k) (i32.const 0)))
|
|
195
|
+
(local.set $pow2 (f64.mul (local.get $pow2) (f64.const 2.0)))
|
|
196
|
+
(local.set $k (i32.add (local.get $k) (i32.const 1)))
|
|
197
|
+
(br $loop2)))
|
|
198
|
+
(local.set $result (f64.div (local.get $result) (local.get $pow2)))))))
|
|
199
|
+
(local.get $result))))))`
|
|
200
|
+
|
|
201
|
+
ctx.core.stdlib['math.expm1'] = `(func $math.expm1 (param $x f64) (result f64)
|
|
202
|
+
(f64.sub (call $math.exp (local.get $x)) (f64.const 1.0)))`
|
|
203
|
+
|
|
204
|
+
ctx.core.stdlib['math.log'] = `(func $math.log (param $x f64) (result f64)
|
|
205
|
+
(local $k i32) (local $y f64) (local $s f64) (local $z f64)
|
|
206
|
+
(if (f64.ne (local.get $x) (local.get $x))
|
|
207
|
+
(then (return (local.get $x))))
|
|
208
|
+
(if (f64.le (local.get $x) (f64.const 0.0))
|
|
209
|
+
(then (return (f64.const 0.0))))
|
|
210
|
+
(if (f64.eq (local.get $x) (f64.const 1.0))
|
|
211
|
+
(then (return (f64.const 0.0))))
|
|
212
|
+
(if (f64.eq (local.get $x) (f64.const inf))
|
|
213
|
+
(then (return (local.get $x))))
|
|
214
|
+
(local.set $k (i32.const 0))
|
|
215
|
+
(local.set $y (local.get $x))
|
|
216
|
+
(block $done_up
|
|
217
|
+
(loop $scale_up
|
|
218
|
+
(br_if $done_up (f64.lt (local.get $y) (f64.const 2.0)))
|
|
219
|
+
(local.set $y (f64.mul (local.get $y) (f64.const 0.5)))
|
|
220
|
+
(local.set $k (i32.add (local.get $k) (i32.const 1)))
|
|
221
|
+
(br $scale_up)))
|
|
222
|
+
(block $done_down
|
|
223
|
+
(loop $scale_down
|
|
224
|
+
(br_if $done_down (f64.ge (local.get $y) (f64.const 1.0)))
|
|
225
|
+
(local.set $y (f64.mul (local.get $y) (f64.const 2.0)))
|
|
226
|
+
(local.set $k (i32.sub (local.get $k) (i32.const 1)))
|
|
227
|
+
(br $scale_down)))
|
|
228
|
+
(local.set $s (f64.div (f64.sub (local.get $y) (f64.const 1.0)) (f64.add (local.get $y) (f64.const 1.0))))
|
|
229
|
+
(local.set $z (f64.mul (local.get $s) (local.get $s)))
|
|
230
|
+
(f64.add
|
|
231
|
+
(f64.mul (f64.convert_i32_s (local.get $k)) (f64.const ${Math.LN2}))
|
|
232
|
+
(f64.mul (f64.const 2.0) (f64.mul (local.get $s) (f64.add (f64.const 1.0)
|
|
233
|
+
(f64.mul (local.get $z) (f64.add (f64.const 0.3333333333333333)
|
|
234
|
+
(f64.mul (local.get $z) (f64.add (f64.const 0.2)
|
|
235
|
+
(f64.mul (local.get $z) (f64.add (f64.const 0.14285714285714285)
|
|
236
|
+
(f64.mul (local.get $z) (f64.add (f64.const 0.1111111111111111)
|
|
237
|
+
(f64.mul (local.get $z) (f64.const 0.09090909090909091)))))))))))))))`
|
|
238
|
+
|
|
239
|
+
ctx.core.stdlib['math.log2'] = `(func $math.log2 (param $x f64) (result f64)
|
|
240
|
+
(f64.div (call $math.log (local.get $x)) (f64.const ${Math.LN2})))`
|
|
241
|
+
|
|
242
|
+
ctx.core.stdlib['math.log10'] = `(func $math.log10 (param $x f64) (result f64)
|
|
243
|
+
(f64.div (call $math.log (local.get $x)) (f64.const ${Math.LN10})))`
|
|
244
|
+
|
|
245
|
+
ctx.core.stdlib['math.log1p'] = `(func $math.log1p (param $x f64) (result f64)
|
|
246
|
+
(call $math.log (f64.add (f64.const 1.0) (local.get $x))))`
|
|
247
|
+
|
|
248
|
+
ctx.core.stdlib['math.pow'] = `(func $math.pow (param $x f64) (param $y f64) (result f64)
|
|
249
|
+
(local $result f64) (local $n i32) (local $neg_base i32) (local $abs_x f64)
|
|
250
|
+
(if (result f64) (f64.eq (local.get $y) (f64.const 0.0))
|
|
251
|
+
(then (f64.const 1.0))
|
|
252
|
+
(else (if (result f64) (f64.eq (local.get $x) (f64.const 0.0))
|
|
253
|
+
(then (f64.const 0.0))
|
|
254
|
+
(else (if (result f64) (f64.eq (local.get $x) (f64.const 1.0))
|
|
255
|
+
(then (f64.const 1.0))
|
|
256
|
+
(else (if (result f64) (f64.eq (local.get $y) (f64.const 1.0))
|
|
257
|
+
(then (local.get $x))
|
|
258
|
+
(else
|
|
259
|
+
(if (result f64)
|
|
260
|
+
(i32.and
|
|
261
|
+
(f64.eq (f64.nearest (local.get $y)) (local.get $y))
|
|
262
|
+
(f64.le (f64.abs (local.get $y)) (f64.const 100.0)))
|
|
263
|
+
(then
|
|
264
|
+
(local.set $abs_x (f64.abs (local.get $x)))
|
|
265
|
+
(local.set $neg_base (i32.and (f64.lt (local.get $x) (f64.const 0.0))
|
|
266
|
+
(i32.and (i32.trunc_f64_s (local.get $y)) (i32.const 1))))
|
|
267
|
+
(local.set $n (i32.trunc_f64_s (f64.abs (local.get $y))))
|
|
268
|
+
(local.set $result (f64.const 1.0))
|
|
269
|
+
(block $done
|
|
270
|
+
(loop $loop
|
|
271
|
+
(br_if $done (i32.le_s (local.get $n) (i32.const 0)))
|
|
272
|
+
(if (i32.and (local.get $n) (i32.const 1))
|
|
273
|
+
(then (local.set $result (f64.mul (local.get $result) (local.get $abs_x)))))
|
|
274
|
+
(local.set $abs_x (f64.mul (local.get $abs_x) (local.get $abs_x)))
|
|
275
|
+
(local.set $n (i32.shr_s (local.get $n) (i32.const 1)))
|
|
276
|
+
(br $loop)))
|
|
277
|
+
(if (f64.lt (local.get $y) (f64.const 0.0))
|
|
278
|
+
(then (local.set $result (f64.div (f64.const 1.0) (local.get $result)))))
|
|
279
|
+
(if (local.get $neg_base)
|
|
280
|
+
(then (local.set $result (f64.neg (local.get $result)))))
|
|
281
|
+
(local.get $result))
|
|
282
|
+
(else
|
|
283
|
+
(if (result f64) (f64.lt (local.get $x) (f64.const 0.0))
|
|
284
|
+
(then (f64.const 0.0))
|
|
285
|
+
(else (call $math.exp (f64.mul (local.get $y) (call $math.log (local.get $x)))))))))))))))))`
|
|
286
|
+
|
|
287
|
+
ctx.core.stdlib['math.atan'] = `(func $math.atan (param $x f64) (result f64)
|
|
288
|
+
(local $x2 f64) (local $abs_x f64) (local $reduced f64)
|
|
289
|
+
(local.set $abs_x (f64.abs (local.get $x)))
|
|
290
|
+
(if (result f64) (f64.gt (local.get $abs_x) (f64.const 1.0))
|
|
291
|
+
(then
|
|
292
|
+
(if (result f64) (f64.gt (local.get $x) (f64.const 0.0))
|
|
293
|
+
(then (f64.sub (f64.const ${Math.PI / 2}) (call $math.atan (f64.div (f64.const 1.0) (local.get $x)))))
|
|
294
|
+
(else (f64.add (f64.neg (f64.const ${Math.PI / 2})) (call $math.atan (f64.div (f64.const 1.0) (local.get $x)))))))
|
|
295
|
+
(else
|
|
296
|
+
(if (result f64) (f64.gt (local.get $abs_x) (f64.const 0.5))
|
|
297
|
+
(then
|
|
298
|
+
(local.set $reduced (f64.div (local.get $x) (f64.add (f64.const 1.0) (f64.sqrt (f64.add (f64.const 1.0) (f64.mul (local.get $x) (local.get $x)))))))
|
|
299
|
+
(f64.mul (f64.const 2.0) (call $math.atan (local.get $reduced))))
|
|
300
|
+
(else
|
|
301
|
+
(local.set $x2 (f64.mul (local.get $x) (local.get $x)))
|
|
302
|
+
(f64.mul (local.get $x)
|
|
303
|
+
(f64.sub (f64.const 1.0)
|
|
304
|
+
(f64.mul (local.get $x2)
|
|
305
|
+
(f64.sub (f64.const 0.3333333333333333)
|
|
306
|
+
(f64.mul (local.get $x2)
|
|
307
|
+
(f64.sub (f64.const 0.2)
|
|
308
|
+
(f64.mul (local.get $x2)
|
|
309
|
+
(f64.sub (f64.const 0.14285714285714285)
|
|
310
|
+
(f64.mul (local.get $x2)
|
|
311
|
+
(f64.sub (f64.const 0.1111111111111111)
|
|
312
|
+
(f64.mul (local.get $x2)
|
|
313
|
+
(f64.sub (f64.const 0.09090909090909091)
|
|
314
|
+
(f64.mul (local.get $x2) (f64.const 0.07692307692307693)))))))))))))))))))`
|
|
315
|
+
|
|
316
|
+
ctx.core.stdlib['math.asin'] = `(func $math.asin (param $x f64) (result f64)
|
|
317
|
+
(if (result f64) (f64.gt (f64.abs (local.get $x)) (f64.const 1.0))
|
|
318
|
+
(then (f64.const 0.0))
|
|
319
|
+
(else (call $math.atan (f64.div (local.get $x)
|
|
320
|
+
(f64.sqrt (f64.sub (f64.const 1.0) (f64.mul (local.get $x) (local.get $x)))))))))`
|
|
321
|
+
|
|
322
|
+
ctx.core.stdlib['math.acos'] = `(func $math.acos (param $x f64) (result f64)
|
|
323
|
+
(f64.sub (f64.const ${Math.PI / 2}) (call $math.asin (local.get $x))))`
|
|
324
|
+
|
|
325
|
+
ctx.core.stdlib['math.atan2'] = `(func $math.atan2 (param $y f64) (param $x f64) (result f64)
|
|
326
|
+
(if (result f64) (f64.eq (local.get $x) (f64.const 0.0)) (then
|
|
327
|
+
(if (result f64) (f64.eq (local.get $y) (f64.const 0.0)) (then (f64.const 0.0)) (else
|
|
328
|
+
(if (result f64) (f64.gt (local.get $y) (f64.const 0.0)) (then (f64.const ${Math.PI / 2})) (else (f64.neg (f64.const ${Math.PI / 2})))))))
|
|
329
|
+
(else (if (result f64) (f64.ge (local.get $x) (f64.const 0.0))
|
|
330
|
+
(then (call $math.atan (f64.div (local.get $y) (local.get $x))))
|
|
331
|
+
(else (if (result f64) (f64.ge (local.get $y) (f64.const 0.0))
|
|
332
|
+
(then (f64.add (call $math.atan (f64.div (local.get $y) (local.get $x))) (f64.const ${Math.PI})))
|
|
333
|
+
(else (f64.sub (call $math.atan (f64.div (local.get $y) (local.get $x))) (f64.const ${Math.PI})))))))))`
|
|
334
|
+
|
|
335
|
+
ctx.core.stdlib['math.sinh'] = `(func $math.sinh (param $x f64) (result f64)
|
|
336
|
+
(local $ex f64)
|
|
337
|
+
(local.set $ex (call $math.exp (f64.abs (local.get $x))))
|
|
338
|
+
(local.set $ex (f64.mul (f64.const 0.5) (f64.sub (local.get $ex) (f64.div (f64.const 1.0) (local.get $ex)))))
|
|
339
|
+
(if (result f64) (f64.lt (local.get $x) (f64.const 0.0)) (then (f64.neg (local.get $ex))) (else (local.get $ex))))`
|
|
340
|
+
|
|
341
|
+
ctx.core.stdlib['math.cosh'] = `(func $math.cosh (param $x f64) (result f64)
|
|
342
|
+
(local $ex f64) (local.set $ex (call $math.exp (f64.abs (local.get $x))))
|
|
343
|
+
(f64.mul (f64.const 0.5) (f64.add (local.get $ex) (f64.div (f64.const 1.0) (local.get $ex)))))`
|
|
344
|
+
|
|
345
|
+
ctx.core.stdlib['math.tanh'] = `(func $math.tanh (param $x f64) (result f64)
|
|
346
|
+
(local $e2x f64)
|
|
347
|
+
(if (result f64) (f64.gt (f64.abs (local.get $x)) (f64.const 22.0))
|
|
348
|
+
(then (if (result f64) (f64.lt (local.get $x) (f64.const 0.0)) (then (f64.const -1.0)) (else (f64.const 1.0))))
|
|
349
|
+
(else (local.set $e2x (call $math.exp (f64.mul (f64.const 2.0) (f64.abs (local.get $x)))))
|
|
350
|
+
(local.set $e2x (f64.div (f64.sub (local.get $e2x) (f64.const 1.0)) (f64.add (local.get $e2x) (f64.const 1.0))))
|
|
351
|
+
(if (result f64) (f64.lt (local.get $x) (f64.const 0.0)) (then (f64.neg (local.get $e2x))) (else (local.get $e2x))))))`
|
|
352
|
+
|
|
353
|
+
ctx.core.stdlib['math.asinh'] = `(func $math.asinh (param $x f64) (result f64)
|
|
354
|
+
(call $math.log (f64.add (local.get $x) (f64.sqrt (f64.add (f64.mul (local.get $x) (local.get $x)) (f64.const 1.0))))))`
|
|
355
|
+
|
|
356
|
+
ctx.core.stdlib['math.acosh'] = `(func $math.acosh (param $x f64) (result f64)
|
|
357
|
+
(if (result f64) (f64.lt (local.get $x) (f64.const 1.0)) (then (f64.const 0.0)) (else
|
|
358
|
+
(call $math.log (f64.add (local.get $x) (f64.sqrt (f64.sub (f64.mul (local.get $x) (local.get $x)) (f64.const 1.0))))))))`
|
|
359
|
+
|
|
360
|
+
ctx.core.stdlib['math.atanh'] = `(func $math.atanh (param $x f64) (result f64)
|
|
361
|
+
(f64.mul (f64.const 0.5) (call $math.log (f64.div (f64.add (f64.const 1.0) (local.get $x)) (f64.sub (f64.const 1.0) (local.get $x))))))`
|
|
362
|
+
|
|
363
|
+
ctx.core.stdlib['math.cbrt'] = `(func $math.cbrt (param $x f64) (result f64)
|
|
364
|
+
(local $y f64)
|
|
365
|
+
(if (result f64) (f64.lt (local.get $x) (f64.const 0.0))
|
|
366
|
+
(then (f64.neg (call $math.cbrt (f64.neg (local.get $x)))))
|
|
367
|
+
(else (if (result f64) (f64.eq (local.get $x) (f64.const 0.0))
|
|
368
|
+
(then (f64.const 0.0))
|
|
369
|
+
(else
|
|
370
|
+
;; Initial guess via pow, then Newton-Raphson: y = (2y + x/y²)/3
|
|
371
|
+
(local.set $y (call $math.pow (local.get $x) (f64.const 0.3333333333333333)))
|
|
372
|
+
(local.set $y (f64.div (f64.add (f64.mul (f64.const 2.0) (local.get $y)) (f64.div (local.get $x) (f64.mul (local.get $y) (local.get $y)))) (f64.const 3.0)))
|
|
373
|
+
(local.set $y (f64.div (f64.add (f64.mul (f64.const 2.0) (local.get $y)) (f64.div (local.get $x) (f64.mul (local.get $y) (local.get $y)))) (f64.const 3.0)))
|
|
374
|
+
(local.get $y))))))`
|
|
375
|
+
|
|
376
|
+
ctx.core.stdlib['math.hypot'] = `(func $math.hypot (param $x f64) (param $y f64) (result f64)
|
|
377
|
+
(f64.sqrt (f64.add (f64.mul (local.get $x) (local.get $x)) (f64.mul (local.get $y) (local.get $y)))))`
|
|
378
|
+
|
|
379
|
+
ctx.core.stdlib['math.random'] = `(func $math.random (result f64)
|
|
380
|
+
(local $s i32)
|
|
381
|
+
(local.set $s (global.get $math.rng_state))
|
|
382
|
+
(local.set $s (i32.xor (local.get $s) (i32.shl (local.get $s) (i32.const 13))))
|
|
383
|
+
(local.set $s (i32.xor (local.get $s) (i32.shr_u (local.get $s) (i32.const 17))))
|
|
384
|
+
(local.set $s (i32.xor (local.get $s) (i32.shl (local.get $s) (i32.const 5))))
|
|
385
|
+
(global.set $math.rng_state (local.get $s))
|
|
386
|
+
(f64.div (f64.convert_i32_u (i32.and (local.get $s) (i32.const 0x7FFFFFFF))) (f64.const 2147483647.0)))`
|
|
387
|
+
|
|
388
|
+
// Global for random state
|
|
389
|
+
ctx.scope.globals.set('math.rng_state', '(global $math.rng_state (mut i32) (i32.const 12345))')
|
|
390
|
+
}
|