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 +1 -1
- package/types/bigint/module.f.js +17 -7
- package/types/bigint/test.f.js +45 -0
package/package.json
CHANGED
package/types/bigint/module.f.js
CHANGED
|
@@ -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 =
|
|
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 !==
|
|
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 <<
|
|
84
|
+
// We know that `v` is less than `1n << 1024` so we can calculate a remainder using
|
|
83
85
|
// `Math.log2`.
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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.
|
package/types/bigint/test.f.js
CHANGED
|
@@ -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)]));
|