porffor 0.55.13 → 0.55.14
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/compiler/builtins/math.ts +86 -2
- package/compiler/builtins/porffor.d.ts +4 -0
- package/compiler/builtins.js +19 -0
- package/compiler/builtins_precompiled.js +357 -350
- package/package.json +1 -1
- package/runner/index.js +1 -1
@@ -137,6 +137,11 @@ export const __Math_pow = (base: number, exponent: number): number => {
|
|
137
137
|
// 2. If exponent is either +0𝔽 or -0𝔽, return 1𝔽.
|
138
138
|
if (exponent == 0) return 1;
|
139
139
|
|
140
|
+
// opt: use bit shift for base 2
|
141
|
+
if (base == 2) {
|
142
|
+
if (Porffor.fastAnd(Number.isInteger(exponent), exponent > 0, exponent < 31)) return 2 << (exponent - 1);
|
143
|
+
}
|
144
|
+
|
140
145
|
if (!Number.isFinite(base)) {
|
141
146
|
// 3. If base is NaN, return NaN.
|
142
147
|
if (Number.isNaN(base)) return base;
|
@@ -259,7 +264,7 @@ export const __Math_expm1 = (x: number): number => {
|
|
259
264
|
return x;
|
260
265
|
}
|
261
266
|
|
262
|
-
// use exp(x) - 1 for large x
|
267
|
+
// opt: use exp(x) - 1 for large x
|
263
268
|
if (Math.abs(x) > 1e-5) return Math.exp(x) - 1;
|
264
269
|
|
265
270
|
// Taylor series
|
@@ -280,7 +285,7 @@ export const __Math_log1p = (x: number): number => {
|
|
280
285
|
if (x == -1) return -Infinity; // log(0) = -inf
|
281
286
|
if (!Number.isFinite(x)) return x;
|
282
287
|
|
283
|
-
// use exp(x) - 1 for large x
|
288
|
+
// opt: use exp(x) - 1 for large x
|
284
289
|
if (Math.abs(x) > 1e-5) return Math.log(1 + x);
|
285
290
|
|
286
291
|
// Taylor series
|
@@ -454,4 +459,83 @@ export const __Math_atan2 = (y: number, x: number): number => {
|
|
454
459
|
|
455
460
|
if (y >= 0) return Math.atan(ratio) + Math.PI;
|
456
461
|
return Math.atan(ratio) - Math.PI;
|
462
|
+
};
|
463
|
+
|
464
|
+
export const __Math_sumPrecise = (values: any[]): number => {
|
465
|
+
// based on "Fast exact summation using small and large superaccumulators" by Radford M. Neal
|
466
|
+
// https://arxiv.org/abs/1505.05571
|
467
|
+
// accuracy is top priority, it is fine for this to be slow(er)
|
468
|
+
|
469
|
+
// small superaccumulator uses 67 chunks: (1 << (11 - 5)) + 3
|
470
|
+
// 11 is the number of exponent bits in IEEE-754 double precision
|
471
|
+
// 5 is the number of low-order exponent bits stored per chunk
|
472
|
+
const SMALL_SLOTS: number = 67;
|
473
|
+
const SMALL_MIN: number = -970;
|
474
|
+
const small: Float64Array = new Float64Array(SMALL_SLOTS);
|
475
|
+
|
476
|
+
// large superaccumulator uses 4096 chunks: 1 << (11 + 1)
|
477
|
+
// 11 is the number of exponent bits in IEEE-754 double precision
|
478
|
+
const LARGE_SLOTS: number = 4096;
|
479
|
+
const LARGE_MIN: number = -1074;
|
480
|
+
const large: Float64Array = new Float64Array(LARGE_SLOTS);
|
481
|
+
|
482
|
+
for (const _ of values) {
|
483
|
+
if (Porffor.rawType(_) != Porffor.TYPES.number) throw new TypeError('Math.sumPrecise must have only numbers in values');
|
484
|
+
|
485
|
+
const v: number = _;
|
486
|
+
if (v == 0) continue;
|
487
|
+
|
488
|
+
const exp: number = Porffor.number.getExponent(v);
|
489
|
+
|
490
|
+
// check if value fits in small superaccumulator
|
491
|
+
if (exp >= SMALL_MIN && exp < SMALL_MIN + SMALL_SLOTS) {
|
492
|
+
// map the exponent to an array index (-970 -> 0, -969 -> 1, etc)
|
493
|
+
const slot: number = exp - SMALL_MIN;
|
494
|
+
let y: number = v;
|
495
|
+
|
496
|
+
// cascade up through slots, similar to carrying digits in decimal
|
497
|
+
// but operating in binary and handling floating point carefully
|
498
|
+
for (let i: number = slot; i < SMALL_SLOTS - 1; i++) {
|
499
|
+
const sum: number = small[i] + y;
|
500
|
+
y = sum;
|
501
|
+
|
502
|
+
// a number fits in slot i if its magnitude is less than 2^(i+SMALL_MIN+1)
|
503
|
+
const slotLimit: number = Math.pow(2, i + SMALL_MIN + 1);
|
504
|
+
if (y >= -slotLimit && y < slotLimit) {
|
505
|
+
small[i] = y;
|
506
|
+
y = 0;
|
507
|
+
break;
|
508
|
+
}
|
509
|
+
|
510
|
+
// doesn't fit, clear this slot and continue cascading
|
511
|
+
small[i] = 0;
|
512
|
+
}
|
513
|
+
|
514
|
+
// if we still have a non-zero value after cascading through small,
|
515
|
+
// it needs to go into the large superaccumulator
|
516
|
+
if (y != 0) {
|
517
|
+
large[Porffor.number.getExponent(y) - LARGE_MIN] += y;
|
518
|
+
}
|
519
|
+
} else {
|
520
|
+
// exponent is outside small superaccumulator range,
|
521
|
+
// put it directly in the large superaccumulator
|
522
|
+
large[Porffor.number.getExponent(v) - LARGE_MIN] += v;
|
523
|
+
}
|
524
|
+
}
|
525
|
+
|
526
|
+
// combine results from both superaccumulators,
|
527
|
+
// process from highest to lowest to maintain precision
|
528
|
+
// todo: handle -0 (see test262 test)
|
529
|
+
let sum: number = -0;
|
530
|
+
for (let i: number = LARGE_SLOTS - 1; i >= 0; i--) {
|
531
|
+
sum += large[i];
|
532
|
+
}
|
533
|
+
|
534
|
+
for (let i: number = SMALL_SLOTS - 1; i >= 0; i--) {
|
535
|
+
sum += small[i];
|
536
|
+
}
|
537
|
+
|
538
|
+
// todo: free large and small
|
539
|
+
|
540
|
+
return sum;
|
457
541
|
};
|
package/compiler/builtins.js
CHANGED
@@ -1025,5 +1025,24 @@ export const BuiltinFuncs = function() {
|
|
1025
1025
|
table: true
|
1026
1026
|
};
|
1027
1027
|
|
1028
|
+
this.__Porffor_number_getExponent = {
|
1029
|
+
params: [ Valtype.f64 ],
|
1030
|
+
returns: [ Valtype.i32 ],
|
1031
|
+
returnType: TYPES.number,
|
1032
|
+
wasm: [
|
1033
|
+
// extract exponent bits from f64 with bit manipulation
|
1034
|
+
[ Opcodes.local_get, 0 ],
|
1035
|
+
[ Opcodes.i64_reinterpret_f64 ],
|
1036
|
+
number(52, Valtype.i64),
|
1037
|
+
[ Opcodes.i64_shr_u ],
|
1038
|
+
number(0x7FF, Valtype.i64),
|
1039
|
+
[ Opcodes.i64_and ],
|
1040
|
+
[ Opcodes.i32_wrap_i64 ],
|
1041
|
+
number(1023, Valtype.i32),
|
1042
|
+
[ Opcodes.i32_sub ]
|
1043
|
+
]
|
1044
|
+
};
|
1045
|
+
|
1046
|
+
|
1028
1047
|
PrecompiledBuiltins.BuiltinFuncs.call(this);
|
1029
1048
|
};
|