functionalscript 0.4.1 → 0.4.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "functionalscript",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "**/*.f.d.ts",
@@ -23,6 +23,8 @@ export const sum = reduce(addition)(0n);
23
23
  export const abs = a => a >= 0 ? a : -a;
24
24
  export const sign = (a) => unsafeCmp(a)(0n);
25
25
  export const serialize = (a) => `${a}n`;
26
+ const { isFinite } = Number;
27
+ const { log2: mathLog2 } = Math;
26
28
  /**
27
29
  * Calculates the base-2 logarithm (floor).
28
30
  *
@@ -52,7 +54,7 @@ export const log2 = (v) => {
52
54
  let result = -1n;
53
55
  // `bigints` higher than 2**1023 may lead to `Inf` during conversion to `number`.
54
56
  // For example: `Number((1n << 1024n) - (1n << 970n)) === Inf`.
55
- let i = 1023n;
57
+ let i = 0x400n;
56
58
  while (true) {
57
59
  const n = v >> i;
58
60
  if (n === 0n) {
@@ -68,7 +70,7 @@ export const log2 = (v) => {
68
70
  //
69
71
  // We know that `v` is not 0 so it doesn't make sense to check `n` when `i` is 0.
70
72
  // Because of this, We check if `i` is greater than 1023 before we divide it by 2.
71
- while (i !== 1023n) {
73
+ while (i !== 0x400n) {
72
74
  i >>= 1n;
73
75
  const n = v >> i;
74
76
  if (n !== 0n) {
@@ -79,12 +81,20 @@ export const log2 = (v) => {
79
81
  //
80
82
  // 3. Remainder Phase.
81
83
  //
82
- // We know that `v` is less than `1n << 1023` so we can calculate a remainder using
84
+ // We know that `v` is less than `1n << 1024` so we can calculate a remainder using
83
85
  // `Math.log2`.
84
- const rem = BigInt(Math.log2(Number(v)) | 0);
85
- // (v >> rem) is either `0` or `1`, and it's used as a correction for
86
- // Math.log2 rounding.
87
- return result + rem + (v >> rem);
86
+ const nl = mathLog2(Number(v));
87
+ if (isFinite(nl)) {
88
+ const rem = BigInt(nl | 0);
89
+ // (v >> rem) is either `0` or `1`, and it's used as a correction for
90
+ // Math.log2 rounding.
91
+ return result + rem + (v >> rem);
92
+ }
93
+ else {
94
+ // nl is Inf, it means log2(v) === 0x3FF and we add +1 to compensate for initial
95
+ // `result = -1n`.
96
+ return result + 0x400n;
97
+ }
88
98
  };
89
99
  /**
90
100
  * Calculates the bit length of a given BigInt.
@@ -64,6 +64,50 @@ export const clz32Log2 = (v) => {
64
64
  }
65
65
  return result - BigInt(Math.clz32(Number(v)));
66
66
  };
67
+ const m1023log2 = (v) => {
68
+ if (v <= 0n) {
69
+ return -1n;
70
+ }
71
+ //
72
+ // 1. Fast Doubling.
73
+ //
74
+ let result = -1n;
75
+ // `bigints` higher than 2**1023 may lead to `Inf` during conversion to `number`.
76
+ // For example: `Number((1n << 1024n) - (1n << 970n)) === Inf`.
77
+ let i = 1023n;
78
+ while (true) {
79
+ const n = v >> i;
80
+ if (n === 0n) {
81
+ // overshot
82
+ break;
83
+ }
84
+ v = n;
85
+ result += i;
86
+ i <<= 1n;
87
+ }
88
+ //
89
+ // 2. Binary Search.
90
+ //
91
+ // We know that `v` is not 0 so it doesn't make sense to check `n` when `i` is 0.
92
+ // Because of this, We check if `i` is greater than 1023 before we divide it by 2.
93
+ while (i !== 1023n) {
94
+ i >>= 1n;
95
+ const n = v >> i;
96
+ if (n !== 0n) {
97
+ result += i;
98
+ v = n;
99
+ }
100
+ }
101
+ //
102
+ // 3. Remainder Phase.
103
+ //
104
+ // We know that `v` is less than `1n << 1023` so we can calculate a remainder using
105
+ // `Math.log2`.
106
+ const rem = BigInt(Math.log2(Number(v)) | 0);
107
+ // (v >> rem) is either `0` or `1`, and it's used as a correction for
108
+ // Math.log2 rounding.
109
+ return result + rem + (v >> rem);
110
+ };
67
111
  const benchmark = f => () => {
68
112
  let e = 1048575n;
69
113
  let c = 1n << e;
@@ -138,6 +182,7 @@ export default {
138
182
  str32Log2,
139
183
  oldLog2,
140
184
  clz32Log2,
185
+ m1023log2,
141
186
  log2,
142
187
  };
143
188
  const transform = (b) => Object.fromEntries(Object.entries(list).map(([k, f]) => [k, b(f)]));