porffor 0.14.0-b5a80d8e3 → 0.14.0-b880d42f1
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/CONTRIBUTING.md +4 -2
- package/compiler/2c.js +65 -2
- package/compiler/builtins/annexb_string.ts +1 -0
- package/compiler/builtins/array.ts +8 -6
- package/compiler/builtins/base64.ts +1 -0
- package/compiler/builtins/boolean.ts +2 -0
- package/compiler/builtins/crypto.ts +1 -0
- package/compiler/builtins/date.ts +2 -0
- package/compiler/builtins/escape.ts +1 -2
- package/compiler/builtins/function.ts +2 -0
- package/compiler/builtins/int.ts +2 -0
- package/compiler/builtins/math.ts +410 -0
- package/compiler/builtins/number.ts +2 -0
- package/compiler/builtins/object.ts +2 -0
- package/compiler/builtins/set.ts +2 -0
- package/compiler/builtins/string.ts +1 -0
- package/compiler/builtins/symbol.ts +2 -0
- package/compiler/builtins.js +26 -4
- package/compiler/codegen.js +120 -140
- package/compiler/generated_builtins.js +217 -10
- package/compiler/index.js +1 -1
- package/compiler/parse.js +1 -1
- package/compiler/precompile.js +2 -2
- package/package.json +1 -1
- package/runner/index.js +4 -3
package/CONTRIBUTING.md
CHANGED
@@ -198,11 +198,13 @@ Store the character code into the `out` pointer variable, and increment it.
|
|
198
198
|
|
199
199
|
## Porffor-specific TS notes
|
200
200
|
|
201
|
-
- For declaring variables, you must use explicit type annotations currently (eg `let a: number = 1`, not `let a = 1`)
|
201
|
+
- For declaring variables, you must use explicit type annotations currently (eg `let a: number = 1`, not `let a = 1`).
|
202
202
|
- You might spot `Porffor.fastOr`/`Porffor.fastAnd`, these are non-short circuiting versions of `||`/`&&`, taking any number of conditions as arguments. You shouldn't don't need to use or worry about these.
|
203
|
-
- **There are ~no objects, you cannot use them
|
203
|
+
- **There are ~no objects, you cannot use them.**
|
204
204
|
- Attempt to avoid string/array-heavy code and use more variables instead if possible, easier on memory and CPU/perf.
|
205
205
|
- Do not set a return type for prototype methods, it can cause errors/unexpected results.
|
206
|
+
- You cannot use other functions in the file not exported, or variables not inside the current function.
|
207
|
+
- `if (...)` uses a fast truthy implementation which is not spec-compliant as most conditions should be strictly checked. To use spec-compliant behavior, use `if (Boolean(...))`.
|
206
208
|
|
207
209
|
<br>
|
208
210
|
|
package/compiler/2c.js
CHANGED
@@ -119,6 +119,9 @@ const removeBrackets = str => {
|
|
119
119
|
};
|
120
120
|
|
121
121
|
export default ({ funcs, globals, tags, data, exceptions, pages }) => {
|
122
|
+
// fix declaring order for c
|
123
|
+
funcs.reverse();
|
124
|
+
|
122
125
|
const invOperatorOpcode = Object.values(operatorOpcode).reduce((acc, x) => {
|
123
126
|
for (const k in x) {
|
124
127
|
acc[x[k]] = k;
|
@@ -156,6 +159,11 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
|
|
156
159
|
prependMain.set('_data', data.map(x => `memcpy(_memory + ${x.offset}, (unsigned char[]){${x.bytes.join(',')}}, ${x.bytes.length});`).join('\n'));
|
157
160
|
}
|
158
161
|
|
162
|
+
if (importFuncs.find(x => x.name === '__Porffor_readArgv')) {
|
163
|
+
prepend.set('argv', `int _argc; char** _argv;`);
|
164
|
+
prependMain.set('argv', `_argc = argc; _argv = argv;`);
|
165
|
+
}
|
166
|
+
|
159
167
|
if (out) out += '\n';
|
160
168
|
|
161
169
|
let depth = 1;
|
@@ -207,8 +215,9 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
|
|
207
215
|
|
208
216
|
const returns = f.returns.length > 0;
|
209
217
|
|
210
|
-
const shouldInline = f.internal;
|
211
|
-
|
218
|
+
const shouldInline = false; // f.internal;
|
219
|
+
if (f.name === 'main') out += `int main(${prependMain.has('argv') ? 'int argc, char* argv[]' : ''}) {\n`;
|
220
|
+
else out += `${f.internal ? (returns ? CValtype.f64 : 'void') : 'struct ReturnValue'} ${shouldInline ? 'inline ' : ''}${sanitize(f.name)}(${f.params.map((x, i) => `${CValtype[x]} ${invLocals[i]}`).join(', ')}) {\n`;
|
212
221
|
|
213
222
|
if (f.name === 'main') {
|
214
223
|
out += [...prependMain.values()].join('\n');
|
@@ -459,6 +468,60 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
|
|
459
468
|
winIncludes.set('windows.h', true);
|
460
469
|
break;
|
461
470
|
|
471
|
+
case '__Porffor_readArgv':
|
472
|
+
includes.set('stdlib.h', true);
|
473
|
+
|
474
|
+
prepend.set('__Porffor_readArgv',
|
475
|
+
`void __Porffor_readArgv(u32 index, u32 outPtr) {
|
476
|
+
if (index >= _argc) {
|
477
|
+
printf("expected %d arguments\\n", index);
|
478
|
+
exit(1);
|
479
|
+
}
|
480
|
+
|
481
|
+
char* arg = _argv[index];
|
482
|
+
|
483
|
+
u32 read = 0;
|
484
|
+
char* out = _memory + outPtr + 4;
|
485
|
+
char ch;
|
486
|
+
while ((ch = *(arg++)) != 0) {
|
487
|
+
out[read++] = ch;
|
488
|
+
}
|
489
|
+
|
490
|
+
memcpy(_memory + outPtr, &read, sizeof(read));
|
491
|
+
}`);
|
492
|
+
|
493
|
+
line(`__Porffor_readArgv((u32)(${vals.at(-2)}), (u32)(${vals.pop()}))`);
|
494
|
+
vals.pop();
|
495
|
+
break;
|
496
|
+
|
497
|
+
case '__Porffor_readFile':
|
498
|
+
includes.set('stdio.h', true);
|
499
|
+
includes.set('stdlib.h', true);
|
500
|
+
|
501
|
+
prepend.set('__Porffor_readFile',
|
502
|
+
`void __Porffor_readFile(u32 pathPtr, u32 outPtr) {
|
503
|
+
char* path = _memory + pathPtr + 4;
|
504
|
+
FILE* fp = fopen(path, "r");
|
505
|
+
if (fp == NULL) {
|
506
|
+
printf("failed to open file: %s\\n", path);
|
507
|
+
exit(1);
|
508
|
+
}
|
509
|
+
|
510
|
+
u32 read = 0;
|
511
|
+
char* out = _memory + outPtr + 4;
|
512
|
+
char ch;
|
513
|
+
while ((ch = fgetc(fp)) != EOF) {
|
514
|
+
out[read++] = ch;
|
515
|
+
}
|
516
|
+
|
517
|
+
fclose(fp);
|
518
|
+
|
519
|
+
memcpy(_memory + outPtr, &read, sizeof(read));
|
520
|
+
}`);
|
521
|
+
line(`__Porffor_readFile((u32)(${vals.at(-2)}), (u32)(${vals.pop()}))`);
|
522
|
+
vals.pop();
|
523
|
+
break;
|
524
|
+
|
462
525
|
default:
|
463
526
|
log.warning('2c', `unimplemented import: ${importFunc.name}`);
|
464
527
|
break;
|
@@ -1,3 +1,5 @@
|
|
1
|
+
import type {} from './porffor.d.ts';
|
2
|
+
|
1
3
|
export const __Array_isArray = (x: unknown): boolean =>
|
2
4
|
// Porffor.wasm`local.get ${x+1}` == Porffor.TYPES.array;
|
3
5
|
Porffor.rawType(x) == Porffor.TYPES.array;
|
@@ -162,7 +164,7 @@ export const __Array_prototype_filter = (_this: any[], callbackFn: any) => {
|
|
162
164
|
let i: i32 = 0;
|
163
165
|
while (i < len) {
|
164
166
|
const el: any = _this[i];
|
165
|
-
if (callbackFn(el, i++, _this)) out.push(el);
|
167
|
+
if (Boolean(callbackFn(el, i++, _this))) out.push(el);
|
166
168
|
}
|
167
169
|
|
168
170
|
return out;
|
@@ -185,7 +187,7 @@ export const __Array_prototype_find = (_this: any[], callbackFn: any) => {
|
|
185
187
|
let i: i32 = 0;
|
186
188
|
while (i < len) {
|
187
189
|
const el: any = _this[i];
|
188
|
-
if (callbackFn(el, i++, _this)) return el;
|
190
|
+
if (Boolean(callbackFn(el, i++, _this))) return el;
|
189
191
|
}
|
190
192
|
};
|
191
193
|
|
@@ -193,7 +195,7 @@ export const __Array_prototype_findLast = (_this: any[], callbackFn: any) => {
|
|
193
195
|
let i: i32 = _this.length;
|
194
196
|
while (i > 0) {
|
195
197
|
const el: any = _this[--i];
|
196
|
-
if (callbackFn(el, i, _this)) return el;
|
198
|
+
if (Boolean(callbackFn(el, i, _this))) return el;
|
197
199
|
}
|
198
200
|
};
|
199
201
|
|
@@ -201,14 +203,14 @@ export const __Array_prototype_findIndex = (_this: any[], callbackFn: any) => {
|
|
201
203
|
const len: i32 = _this.length;
|
202
204
|
let i: i32 = 0;
|
203
205
|
while (i < len) {
|
204
|
-
if (callbackFn(_this[i], i++, _this)) return i;
|
206
|
+
if (Boolean(callbackFn(_this[i], i++, _this))) return i;
|
205
207
|
}
|
206
208
|
};
|
207
209
|
|
208
210
|
export const __Array_prototype_findLastIndex = (_this: any[], callbackFn: any) => {
|
209
211
|
let i: i32 = _this.length;
|
210
212
|
while (i > 0) {
|
211
|
-
if (callbackFn(_this[--i], i, _this)) return i;
|
213
|
+
if (Boolean(callbackFn(_this[--i], i, _this))) return i;
|
212
214
|
}
|
213
215
|
};
|
214
216
|
|
@@ -216,7 +218,7 @@ export const __Array_prototype_every = (_this: any[], callbackFn: any) => {
|
|
216
218
|
const len: i32 = _this.length;
|
217
219
|
let i: i32 = 0;
|
218
220
|
while (i < len) {
|
219
|
-
if (!callbackFn(_this[i], i++, _this)) return false;
|
221
|
+
if (!Boolean(callbackFn(_this[i], i++, _this))) return false;
|
220
222
|
}
|
221
223
|
|
222
224
|
return true;
|
package/compiler/builtins/int.ts
CHANGED
@@ -0,0 +1,410 @@
|
|
1
|
+
import type {} from './porffor.d.ts';
|
2
|
+
|
3
|
+
// todo: use any and Number(x) in all these later
|
4
|
+
// todo: specify the rest of this file later
|
5
|
+
// todo/perf: make i32 variants later
|
6
|
+
// todo/perf: add a compiler pref for accuracy vs perf (epsilion?)
|
7
|
+
|
8
|
+
export const __Math_exp = (x: number): number => {
|
9
|
+
if (!Number.isFinite(x)) {
|
10
|
+
if (x == -Infinity) return 0;
|
11
|
+
return x;
|
12
|
+
}
|
13
|
+
|
14
|
+
if (x < 0) {
|
15
|
+
// exp(-x) = 1 / exp(+x)
|
16
|
+
return 1 / Math.exp(-x);
|
17
|
+
}
|
18
|
+
|
19
|
+
const k: number = Math.floor(x / Math.LN2);
|
20
|
+
const r: number = x - k * Math.LN2;
|
21
|
+
|
22
|
+
// Taylor series via Horner's method
|
23
|
+
let term: number = r;
|
24
|
+
let sum: number = 1 + r;
|
25
|
+
let i: number = 2;
|
26
|
+
|
27
|
+
while (Math.abs(term) > 1e-15) {
|
28
|
+
term *= r / i;
|
29
|
+
sum += term;
|
30
|
+
i++;
|
31
|
+
}
|
32
|
+
|
33
|
+
return sum * (1 << k);
|
34
|
+
};
|
35
|
+
|
36
|
+
export const __Math_log2 = (y: number): number => {
|
37
|
+
if (y <= 0) return NaN;
|
38
|
+
if (!Number.isFinite(y)) return y;
|
39
|
+
|
40
|
+
// approx using log knowledge
|
41
|
+
let x: number = y;
|
42
|
+
let exponent: number = 0;
|
43
|
+
|
44
|
+
while (x >= 2) {
|
45
|
+
x /= 2;
|
46
|
+
exponent++;
|
47
|
+
}
|
48
|
+
|
49
|
+
while (x < 1) {
|
50
|
+
x *= 2;
|
51
|
+
exponent--;
|
52
|
+
}
|
53
|
+
|
54
|
+
// 1 <= x < 2 -> 0 <= x < 1
|
55
|
+
x -= 1;
|
56
|
+
|
57
|
+
// refine with Newton-Raphson method
|
58
|
+
let delta: number;
|
59
|
+
do {
|
60
|
+
const e_x: number = Math.exp(x * Math.LN2);
|
61
|
+
delta = (e_x - y) / (e_x * Math.LN2);
|
62
|
+
x -= delta;
|
63
|
+
} while (Math.abs(delta) > 1e-15);
|
64
|
+
|
65
|
+
return x + exponent;
|
66
|
+
};
|
67
|
+
|
68
|
+
export const __Math_log = (y: number): number => {
|
69
|
+
if (y <= 0) {
|
70
|
+
if (y == 0) return -Infinity;
|
71
|
+
return NaN;
|
72
|
+
}
|
73
|
+
if (!Number.isFinite(y)) return y;
|
74
|
+
|
75
|
+
// guess using log knowledge
|
76
|
+
let x: number = y > 1 ? Math.log2(y) : 0;
|
77
|
+
|
78
|
+
// refine with Newton-Raphson method
|
79
|
+
let delta: number;
|
80
|
+
do {
|
81
|
+
const e_x: number = Math.exp(x);
|
82
|
+
delta = (e_x - y) / e_x;
|
83
|
+
x -= delta;
|
84
|
+
} while (Math.abs(delta) > 1e-15);
|
85
|
+
|
86
|
+
return x;
|
87
|
+
};
|
88
|
+
|
89
|
+
export const __Math_log10 = (x: number): number => {
|
90
|
+
if (x <= 0) {
|
91
|
+
if (x == 0) return -Infinity;
|
92
|
+
return NaN;
|
93
|
+
}
|
94
|
+
if (!Number.isFinite(x)) return x;
|
95
|
+
|
96
|
+
return Math.log(x) / Math.LN10;
|
97
|
+
};
|
98
|
+
|
99
|
+
// 21.3.2.26 Math.pow (base, exponent)
|
100
|
+
// https://tc39.es/ecma262/#sec-math.pow
|
101
|
+
export const __Math_pow = (base: number, exponent: number): number => {
|
102
|
+
// 1. Set base to ? ToNumber(base).
|
103
|
+
// 2. Set exponent to ? ToNumber(exponent).
|
104
|
+
// todo
|
105
|
+
|
106
|
+
// 3. Return Number::exponentiate(base, exponent).
|
107
|
+
|
108
|
+
// Number::exponentiate (base, exponent)
|
109
|
+
// https://tc39.es/ecma262/#sec-numeric-types-number-exponentiate
|
110
|
+
// 1. If exponent is NaN, return NaN.
|
111
|
+
if (Number.isNaN(exponent)) return NaN;
|
112
|
+
|
113
|
+
// 2. If exponent is either +0𝔽 or -0𝔽, return 1𝔽.
|
114
|
+
if (exponent == 0) return 1;
|
115
|
+
|
116
|
+
if (!Number.isFinite(base)) {
|
117
|
+
// 3. If base is NaN, return NaN.
|
118
|
+
if (Number.isNaN(base)) return base;
|
119
|
+
|
120
|
+
// 4. If base is +∞𝔽, then
|
121
|
+
if (base == Infinity) {
|
122
|
+
// a. If exponent > +0𝔽, return +∞𝔽. Otherwise, return +0𝔽.
|
123
|
+
if (exponent > 0) return base;
|
124
|
+
return 0;
|
125
|
+
}
|
126
|
+
|
127
|
+
// 5. If base is -∞𝔽, then
|
128
|
+
const isOdd = exponent % 2 == 1;
|
129
|
+
|
130
|
+
// a. If exponent > +0𝔽, then
|
131
|
+
if (exponent > 0) {
|
132
|
+
// i. If exponent is an odd integral Number, return -∞𝔽. Otherwise, return +∞𝔽.
|
133
|
+
if (isOdd) return -Infinity;
|
134
|
+
return Infinity;
|
135
|
+
}
|
136
|
+
|
137
|
+
// b. Else,
|
138
|
+
// i. If exponent is an odd integral Number, return -0𝔽. Otherwise, return +0𝔽.
|
139
|
+
if (isOdd) return -0;
|
140
|
+
return 0;
|
141
|
+
}
|
142
|
+
|
143
|
+
if (base == 0) {
|
144
|
+
// 6. If base is +0𝔽, then
|
145
|
+
if (1 / base == Infinity) {
|
146
|
+
// a. If exponent > +0𝔽, return +0𝔽. Otherwise, return +∞𝔽.
|
147
|
+
if (exponent > 0) return 0;
|
148
|
+
return Infinity;
|
149
|
+
}
|
150
|
+
|
151
|
+
// 7. If base is -0𝔽, then
|
152
|
+
const isOdd = exponent % 2 == 1;
|
153
|
+
|
154
|
+
// a. If exponent > +0𝔽, then
|
155
|
+
if (exponent > 0) {
|
156
|
+
// i. If exponent is an odd integral Number, return -0𝔽. Otherwise, return +0𝔽.
|
157
|
+
if (isOdd) return -0;
|
158
|
+
return 0;
|
159
|
+
}
|
160
|
+
|
161
|
+
// b. Else,
|
162
|
+
// i. If exponent is an odd integral Number, return -∞𝔽. Otherwise, return +∞𝔽.
|
163
|
+
if (isOdd) return -Infinity;
|
164
|
+
return Infinity;
|
165
|
+
}
|
166
|
+
|
167
|
+
// 8. Assert: base is finite and is neither +0𝔽 nor -0𝔽.
|
168
|
+
// todo
|
169
|
+
|
170
|
+
// 9. If exponent is +∞𝔽, then
|
171
|
+
if (exponent == Infinity) {
|
172
|
+
const abs = Math.abs(base);
|
173
|
+
|
174
|
+
// a. If abs(ℝ(base)) > 1, return +∞𝔽.
|
175
|
+
if (abs > 1) return Infinity;
|
176
|
+
|
177
|
+
// b. If abs(ℝ(base)) = 1, return NaN.
|
178
|
+
if (abs == 1) return NaN;
|
179
|
+
|
180
|
+
// c. If abs(ℝ(base)) < 1, return +0𝔽.
|
181
|
+
return 0;
|
182
|
+
}
|
183
|
+
|
184
|
+
// 10. If exponent is -∞𝔽, then
|
185
|
+
if (exponent == -Infinity) {
|
186
|
+
const abs = Math.abs(base);
|
187
|
+
|
188
|
+
// a. If abs(ℝ(base)) > 1, return +0𝔽.
|
189
|
+
if (abs > 1) return 0;
|
190
|
+
|
191
|
+
// b. If abs(ℝ(base)) = 1, return NaN.
|
192
|
+
if (abs == 1) return NaN;
|
193
|
+
|
194
|
+
// c. If abs(ℝ(base)) < 1, return +∞𝔽.
|
195
|
+
return Infinity;
|
196
|
+
}
|
197
|
+
|
198
|
+
// 11. Assert: exponent is finite and is neither +0𝔽 nor -0𝔽.
|
199
|
+
// todo
|
200
|
+
|
201
|
+
// 12. If base < -0𝔽 and exponent is not an integral Number, return NaN.
|
202
|
+
if (base < 0) if (!Number.isInteger(exponent)) return NaN;
|
203
|
+
|
204
|
+
// 13. Return an implementation-approximated Number value representing the result of raising ℝ(base) to the ℝ(exponent) power.
|
205
|
+
return Math.exp(exponent * Math.log(base));
|
206
|
+
};
|
207
|
+
|
208
|
+
|
209
|
+
export const __Math_expm1 = (x: number): number => {
|
210
|
+
if (!Number.isFinite(x)) {
|
211
|
+
if (x == -Infinity) return -1;
|
212
|
+
return x;
|
213
|
+
}
|
214
|
+
|
215
|
+
// use exp(x) - 1 for large x (perf)
|
216
|
+
if (Math.abs(x) > 1e-5) return Math.exp(x) - 1;
|
217
|
+
|
218
|
+
// Taylor series
|
219
|
+
let sum: number = x;
|
220
|
+
let term: number = x;
|
221
|
+
let i: number = 2;
|
222
|
+
|
223
|
+
while (Math.abs(term) > 1e-15) {
|
224
|
+
term *= x / i;
|
225
|
+
sum += term;
|
226
|
+
i++;
|
227
|
+
}
|
228
|
+
|
229
|
+
return sum;
|
230
|
+
};
|
231
|
+
|
232
|
+
export const __Math_log1p = (x: number): number => {
|
233
|
+
if (x == -1) return -Infinity; // log(0) = -inf
|
234
|
+
if (!Number.isFinite(x)) return x;
|
235
|
+
|
236
|
+
// use exp(x) - 1 for large x (perf)
|
237
|
+
if (Math.abs(x) > 1e-5) return Math.log(1 + x);
|
238
|
+
|
239
|
+
// Taylor series
|
240
|
+
let sum: number = 0;
|
241
|
+
let term: number = x;
|
242
|
+
let i: number = 2;
|
243
|
+
|
244
|
+
while (Math.abs(term) > 1e-15) {
|
245
|
+
term *= -x / i;
|
246
|
+
sum += term;
|
247
|
+
i++;
|
248
|
+
}
|
249
|
+
|
250
|
+
return sum;
|
251
|
+
};
|
252
|
+
|
253
|
+
|
254
|
+
export const __Math_sqrt = (y: number): number => {
|
255
|
+
if (y <= 0) {
|
256
|
+
if (y == 0) return 0;
|
257
|
+
return NaN;
|
258
|
+
}
|
259
|
+
if (!Number.isFinite(y)) return y;
|
260
|
+
|
261
|
+
// Babylonian method
|
262
|
+
let x: number = y;
|
263
|
+
let prev: number;
|
264
|
+
|
265
|
+
do {
|
266
|
+
prev = x;
|
267
|
+
x = 0.5 * (x + y / x);
|
268
|
+
} while (Math.abs(prev - x) > 1e-15);
|
269
|
+
|
270
|
+
return x;
|
271
|
+
};
|
272
|
+
|
273
|
+
export const __Math_cbrt = (y: number): number => {
|
274
|
+
if (y == 0) return 0; // cbrt(0) = 0
|
275
|
+
if (!Number.isFinite(y)) return y;
|
276
|
+
|
277
|
+
// Babylonian method
|
278
|
+
let x = Math.abs(y);
|
279
|
+
|
280
|
+
let prev: number;
|
281
|
+
|
282
|
+
do {
|
283
|
+
prev = x;
|
284
|
+
x = (2 * x + y / (x * x)) / 3;
|
285
|
+
} while (Math.abs(prev - x) > 1e-15);
|
286
|
+
|
287
|
+
return y < 0 ? -x : x;
|
288
|
+
};
|
289
|
+
|
290
|
+
|
291
|
+
// todo: varargs
|
292
|
+
export const __Math_hypot = (x: number, y: number): number => Math.sqrt(x * x + y * y);
|
293
|
+
|
294
|
+
export const __Math_sin = (x: number): number => {
|
295
|
+
// -inf <= x <= inf -> 0 <= x <= 2pi
|
296
|
+
const piX2: number = Math.PI * 2;
|
297
|
+
x %= piX2;
|
298
|
+
if (x < 0) x += piX2;
|
299
|
+
|
300
|
+
const x2: number = x * x;
|
301
|
+
|
302
|
+
return x * (
|
303
|
+
1 + x2 * (
|
304
|
+
-1.66666666666666307295e-1 + x2 * (
|
305
|
+
8.33333333332211858878e-3 + x2 * (
|
306
|
+
-1.98412698295895385996e-4 + x2 * (
|
307
|
+
2.75573136213857245213e-6 + x2 * (
|
308
|
+
-2.50507477628578072866e-8 + x2 * (
|
309
|
+
1.58962301576546568060e-10
|
310
|
+
)
|
311
|
+
)
|
312
|
+
)
|
313
|
+
)
|
314
|
+
)
|
315
|
+
)
|
316
|
+
);
|
317
|
+
|
318
|
+
// todo: investigate which is better (consider perf and accuracy)
|
319
|
+
// const x2 = x * x;
|
320
|
+
// const x4 = x2 * x2;
|
321
|
+
// const x6 = x4 * x2;
|
322
|
+
// const x8 = x4 * x4;
|
323
|
+
// const x10 = x6 * x4;
|
324
|
+
// const x12 = x6 * x6;
|
325
|
+
// const x14 = x12 * x2;
|
326
|
+
|
327
|
+
// return x * (
|
328
|
+
// 1 - x2 / 6 + x4 / 120 - x6 / 5040 + x8 / 362880 - x10 / 39916800 + x12 / 6227020800 - x14 / 1307674368000
|
329
|
+
// );
|
330
|
+
};
|
331
|
+
|
332
|
+
export const __Math_cos = (x: number): number => Math.sin(x - Math.PI / 2);
|
333
|
+
export const __Math_tan = (x: number): number => Math.sin(x) / Math.cos(x);
|
334
|
+
|
335
|
+
export const __Math_sinh = (x: number): number => (Math.exp(x) - Math.exp(-x)) / 2;
|
336
|
+
export const __Math_cosh = (x: number): number => (Math.exp(x) + Math.exp(-x)) / 2;
|
337
|
+
export const __Math_tanh = (x: number): number => Math.sinh(x) / Math.cosh(x);
|
338
|
+
|
339
|
+
|
340
|
+
export const __Math_asinh = (x: number): number => Math.log(x + Math.sqrt(x * x + 1));
|
341
|
+
export const __Math_acosh = (x: number): number => {
|
342
|
+
if (x < 1) return NaN;
|
343
|
+
return Math.log(x + Math.sqrt(x * x - 1));
|
344
|
+
};
|
345
|
+
export const __Math_atanh = (x: number): number => {
|
346
|
+
if (Math.abs(x) >= 1) return NaN;
|
347
|
+
return 0.5 * Math.log((1 + x) / (1 - x));
|
348
|
+
};
|
349
|
+
|
350
|
+
|
351
|
+
export const __Math_asin = (x: number): number => {
|
352
|
+
if (x <= -1) {
|
353
|
+
if (x == -1) return -Math.PI / 2;
|
354
|
+
return NaN;
|
355
|
+
}
|
356
|
+
if (x >= 1) {
|
357
|
+
if (x == 1) return Math.PI / 2;
|
358
|
+
return NaN;
|
359
|
+
}
|
360
|
+
|
361
|
+
// Taylor series
|
362
|
+
let sum: number = x;
|
363
|
+
let term: number = x;
|
364
|
+
let n: number = 1;
|
365
|
+
|
366
|
+
while (Math.abs(term) > 1e-15) {
|
367
|
+
term *= x * x * (2 * n - 1) * (2 * n - 1) / ((2 * n) * (2 * n + 1));
|
368
|
+
sum += term / (2 * n + 1);
|
369
|
+
n++;
|
370
|
+
}
|
371
|
+
|
372
|
+
return sum;
|
373
|
+
};
|
374
|
+
|
375
|
+
export const __Math_acos = (x: number): number => Math.asin(x) - Math.PI / 2;
|
376
|
+
|
377
|
+
export const __Math_atan = (x: number): number => {
|
378
|
+
if (x == Infinity) return Math.PI / 2
|
379
|
+
if (x == -Infinity) return -Math.PI / 2;
|
380
|
+
|
381
|
+
// Taylor series
|
382
|
+
let sum: number = x;
|
383
|
+
let term: number = x;
|
384
|
+
let n: number = 1;
|
385
|
+
|
386
|
+
while (Math.abs(term) > 1e-15) {
|
387
|
+
term *= -x * x * (2 * n - 1) / ((2 * n) * (2 * n + 1));
|
388
|
+
sum += term;
|
389
|
+
n++;
|
390
|
+
}
|
391
|
+
|
392
|
+
return sum;
|
393
|
+
};
|
394
|
+
|
395
|
+
export const __Math_atan2 = (y: number, x: number): number => {
|
396
|
+
if (x == 0) {
|
397
|
+
if (y > 0) return Math.PI / 2;
|
398
|
+
if (y < 0) return -Math.PI / 2;
|
399
|
+
|
400
|
+
return NaN;
|
401
|
+
}
|
402
|
+
|
403
|
+
const ratio = y / x;
|
404
|
+
if (x > 0) {
|
405
|
+
return Math.atan(ratio);
|
406
|
+
}
|
407
|
+
|
408
|
+
if (y >= 0) return Math.atan(ratio) + Math.PI;
|
409
|
+
return Math.atan(ratio) - Math.PI;
|
410
|
+
};
|
package/compiler/builtins/set.ts
CHANGED