functionalscript 0.0.569 → 0.0.571

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.0.569",
3
+ "version": "0.0.571",
4
4
  "description": "FunctionalScript is a functional subset of JavaScript",
5
5
  "scripts": {
6
6
  "tsc": "tsc",
@@ -0,0 +1,35 @@
1
+ # BigInt
2
+
3
+ Bun has a `bigint` size limitation. It's `1_048_575` bits (`1024 ** 2`) or `131_072` Bytes.
4
+
5
+ ## Benchmarks
6
+
7
+ ### bitLen vs toString(2).length (2024/11/25)
8
+
9
+ |Framework|bitLen |toString(2).length|
10
+ |---------|------------------|------------------|
11
+ |Bun |1.781681 |2.079615 |
12
+ |Deno 1 |0.710344 |1.917003 |
13
+ |Deno 2 |0.986602 |2.286932 |
14
+ |Node 16 |1.521150 |2.330505 |
15
+ |Node 18 |1.393006 |2.312573 |
16
+ |Node 20 |1.055315 |2.320039 |
17
+ |Node 22 |0.983075 |2.336697 |
18
+ |Node 23 |0.699960 |1.872965 |
19
+
20
+ `bitLen` wins.
21
+
22
+ ### Minus vs Not
23
+
24
+ |Framework|minus `-` |not `~` |
25
+ |---------|------------------|------------------|
26
+ |Bun |86.269967 | 80.372970 |
27
+ |Deno 1 |18.754810 | 59.498217 |
28
+ |Deno 2 |17.262486 | 57.157273 |
29
+ |Node 16 |70.350582 |121.023162 |
30
+ |Node 18 |61.039463 | 99.369215 |
31
+ |Node 20 |16.908695 | 63.335552 |
32
+ |Node 22 |19.546644 | 59.034978 |
33
+ |Node 23 |18.246697 | 58.825815 |
34
+
35
+ `-` wins.
@@ -44,17 +44,61 @@ const scalar_mul = ({ 0: _0, add }) => a => n => {
44
44
  }
45
45
  }
46
46
 
47
- /** @type {(a: bigint) => bigint} */
48
- const log2 = a => {
49
- // Possible optimization: use a binary search in 32 bit value
50
- let i = -1n
51
- while (a > 0n) {
52
- ++i
53
- a >>= 1n
47
+ /**
48
+ * Calculates the bit length of a given BigInt.
49
+ *
50
+ * The bit length of a number is the number of bits required to represent it in binary,
51
+ * excluding leading zeros. For example:
52
+ * - `0n` (binary `...0`) has a bit length of 0.
53
+ * - `1n` (binary `...0_1`) has a bit length of 1.
54
+ * - `255n` (binary `...0_11111111`) has a bit length of 8.
55
+ *
56
+ * Negative inputs are converted to their absolute values before calculation. For example:
57
+ * - `-255n` has a bit length of 8.
58
+ * - `-1n` has a bit length of 1.
59
+ *
60
+ * @param {bigint} v - The input BigInt. It can be positive, negative, or zero.
61
+ * @returns {bigint} The bit length of the input BigInt.
62
+ *
63
+ * @remarks
64
+ * This function determines the bit length in two phases:
65
+ * 1. **Fast Doubling Phase:** Quickly identifies the range of the most significant bit using exponential steps.
66
+ * 2. **Binary Search Phase:** Refines the result to precisely count all significant bits.
67
+ *
68
+ * The algorithm operates with logarithmic complexity, making it efficient for very large BigInts.
69
+ */
70
+ const bitLen = v => {
71
+ if (v <= 0n) {
72
+ if (v === 0n) { return 0n }
73
+ v = -v
74
+ }
75
+ let result = 1n
76
+ let i = 1n
77
+ while (true) {
78
+ const n = v >> i
79
+ if (n === 0n) {
80
+ // overshot
81
+ break
82
+ }
83
+ v = n
84
+ result += i
85
+ i <<= 1n
86
+ }
87
+ // We know that `v` is not 0 so it doesn't make sense to check `n` when `i` is 0.
88
+ // Because of this, We check if `i` is greater than 1 before we divide it by 2.
89
+ while (i !== 1n) {
90
+ i >>= 1n
91
+ const n = v >> i
92
+ if (n !== 0n) {
93
+ result += i
94
+ v = n
95
+ }
54
96
  }
55
- return i
97
+ return result
56
98
  }
57
99
 
100
+ const log2 = (/** @type {bigint} */v) => v <= 0n ? -1n : bitLen(v) - 1n
101
+
58
102
  module.exports = {
59
103
  /** @readonly */
60
104
  addition,
@@ -70,4 +114,6 @@ module.exports = {
70
114
  scalar_mul,
71
115
  /** @readonly */
72
116
  log2,
117
+ /** @readonly */
118
+ bitLen,
73
119
  }
@@ -1,4 +1,4 @@
1
- const { sum, abs, serialize, log2 } = require('./module.f.cjs')
1
+ const { sum, abs, serialize, log2, bitLen } = require('./module.f.cjs')
2
2
 
3
3
  module.exports = {
4
4
  sum: () => {
@@ -69,6 +69,70 @@ module.exports = {
69
69
  () => {
70
70
  const result = log2(16n)
71
71
  if (result !== 4n) { throw result }
72
+ },
73
+ () => {
74
+ // max for Bun (131_072 Bytes)
75
+ const v = 1_048_575n
76
+ const result = log2(1n << v)
77
+ if (result !== v) { throw result }
78
+ },
79
+ ],
80
+ toString2: () => {
81
+ // max for Bun (131_072 Bytes)
82
+ const v = 1_048_575n
83
+ const result = (1n << v).toString(2).length - 1
84
+ if (result !== 1_048_575) { throw result }
85
+ },
86
+ minus: () => {
87
+ let i = 0n
88
+ while (i < 1_048_575n) {
89
+ const s = -i
90
+ if (i !== -s) { throw [i, s] }
91
+ i += 1n
72
92
  }
73
- ]
93
+ },
94
+ not: () => {
95
+ let i = 0n
96
+ while (i < 1_048_575n) {
97
+ const s = ~i
98
+ if (i !== ~s) { throw [i, s] }
99
+ i += 1n
100
+ }
101
+ },
102
+ bitLen: {
103
+ 0: () => {
104
+ const s = bitLen(0n)
105
+ if (s !== 0n) { throw s }
106
+ },
107
+ m: () => {
108
+ let i = 0n
109
+ while (i < 10_000n) {
110
+ const s = bitLen(1n << i)
111
+ if (s !== i + 1n) { throw [s, i] }
112
+ i += 1n
113
+ }
114
+ },
115
+ big: () => {
116
+ const s = bitLen(1n << 1_000_000n)
117
+ if (s !== 1_000_001n) { throw s }
118
+ },
119
+ neg: [
120
+ () => {
121
+ const s = bitLen(-1n)
122
+ if (s !== 1n) { throw s }
123
+ },
124
+ () => {
125
+ const s = bitLen(-2n)
126
+ if (s !== 2n) { throw s }
127
+ },
128
+ () => {
129
+ const s = bitLen(-3n)
130
+ if (s !== 2n) { throw s }
131
+ },
132
+ () => {
133
+ const s = bitLen(-4n)
134
+ if (s !== 3n) { throw s }
135
+ },
136
+ ]
137
+ }
74
138
  }