@turing-machine-js/library-binary-numbers 3.0.0 → 3.0.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/CHANGELOG.md +8 -0
- package/package.json +2 -2
- package/dist/index.js +0 -330
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [3.0.2] - 2026-05-04
|
|
8
|
+
|
|
9
|
+
Released in lockstep with `@turing-machine-js/machine` 3.0.2. No source or behavior changes in this package.
|
|
10
|
+
|
|
11
|
+
## [3.0.1] - 2026-04-30
|
|
12
|
+
|
|
13
|
+
Released in lockstep with `@turing-machine-js/machine` 3.0.1. No source or behavior changes in this package.
|
|
14
|
+
|
|
7
15
|
## [3.0.0] - 2026-04-30
|
|
8
16
|
|
|
9
17
|
### Added
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@turing-machine-js/library-binary-numbers",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"description": "A standard library for working with binary numbers",
|
|
5
5
|
"engines": {
|
|
6
6
|
"npm": ">=7.0.0"
|
|
@@ -40,5 +40,5 @@
|
|
|
40
40
|
"default": "./dist/index.mjs"
|
|
41
41
|
}
|
|
42
42
|
},
|
|
43
|
-
"gitHead": "
|
|
43
|
+
"gitHead": "0a78b4d0d40bbdbf79e3c53694adf930f0567b0a"
|
|
44
44
|
}
|
package/dist/index.js
DELETED
|
@@ -1,330 +0,0 @@
|
|
|
1
|
-
import { Alphabet, haltState, ifOtherSymbol, movements, State, symbolCommands, TapeBlock, } from '@turing-machine-js/machine';
|
|
2
|
-
// 5-symbol alphabet: blank (' '), '^' (number start), '$' (number end), '0', '1'.
|
|
3
|
-
// A tape can hold many numbers, each delimited by '^...$', with blanks between.
|
|
4
|
-
//
|
|
5
|
-
// Compared with @turing-machine-js/library-binary-numbers-bare (3-symbol alphabet,
|
|
6
|
-
// single-number-per-tape), the explicit '^'/'$' markers cost extra states per
|
|
7
|
-
// algorithm but enable safe multi-number navigation (goToNumber / goToNextNumber /
|
|
8
|
-
// goToPreviousNumber). Both libraries exist side-by-side so the trade-off between
|
|
9
|
-
// alphabet size and state-graph size is visible — see ../states.md for diagrams.
|
|
10
|
-
const alphabet = new Alphabet(' ^$01'.split(''));
|
|
11
|
-
const tapeBlock = TapeBlock.fromAlphabets([alphabet]);
|
|
12
|
-
const { symbol } = tapeBlock;
|
|
13
|
-
// goToNumber — 2 nodes
|
|
14
|
-
//
|
|
15
|
-
// Walks the head right until '$'. Used as a "go to current number's end" primitive.
|
|
16
|
-
const goToNumber = new State({
|
|
17
|
-
[symbol('$')]: {
|
|
18
|
-
nextState: haltState,
|
|
19
|
-
},
|
|
20
|
-
[ifOtherSymbol]: {
|
|
21
|
-
command: {
|
|
22
|
-
movement: movements.right,
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
}, 'goToNumber');
|
|
26
|
-
// goToNextNumber — 3 nodes (composes goToNumber)
|
|
27
|
-
//
|
|
28
|
-
// Steps right one cell (out of the current '$' / blank gap), then hands off to
|
|
29
|
-
// goToNumber to land on the next number's '$'.
|
|
30
|
-
const goToNextNumber = new State({
|
|
31
|
-
[ifOtherSymbol]: {
|
|
32
|
-
command: {
|
|
33
|
-
movement: movements.right,
|
|
34
|
-
},
|
|
35
|
-
nextState: goToNumber,
|
|
36
|
-
},
|
|
37
|
-
}, 'goToNextNumber');
|
|
38
|
-
// goToPreviousNumber — 3 nodes (uses an internal mirror of goToNumber)
|
|
39
|
-
//
|
|
40
|
-
// Steps left one cell, then walks left until '$' of the previous number.
|
|
41
|
-
const goToPreviousNumberInternal = new State({
|
|
42
|
-
[symbol('$')]: {
|
|
43
|
-
nextState: haltState,
|
|
44
|
-
},
|
|
45
|
-
[ifOtherSymbol]: {
|
|
46
|
-
command: {
|
|
47
|
-
movement: movements.left,
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
|
-
}, 'goToPreviousNumberInternal');
|
|
51
|
-
const goToPreviousNumber = new State({
|
|
52
|
-
[ifOtherSymbol]: {
|
|
53
|
-
command: {
|
|
54
|
-
movement: movements.left,
|
|
55
|
-
},
|
|
56
|
-
nextState: goToPreviousNumberInternal,
|
|
57
|
-
},
|
|
58
|
-
}, 'goToPreviousNumber');
|
|
59
|
-
// goToNumbersStart — 2 nodes
|
|
60
|
-
//
|
|
61
|
-
// Walks the head left until '^'. Mirror of goToNumber for the start marker.
|
|
62
|
-
const goToNumbersStart = new State({
|
|
63
|
-
[symbol('^')]: {
|
|
64
|
-
nextState: haltState,
|
|
65
|
-
},
|
|
66
|
-
[ifOtherSymbol]: {
|
|
67
|
-
command: {
|
|
68
|
-
movement: movements.left,
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
|
-
}, 'goToNumberStart');
|
|
72
|
-
// deleteNumber — 5 nodes
|
|
73
|
-
//
|
|
74
|
-
// Composition: go to the number's '^', then sweep right erasing every cell
|
|
75
|
-
// (digits, '^', '$') until the number is gone. Implemented as
|
|
76
|
-
// goToNumbersStart.withOverrodeHaltState(deleteNumberInternal): when
|
|
77
|
-
// goToNumbersStart would halt at '^', it falls through to the eraser instead.
|
|
78
|
-
const deleteNumberInternal = new State({
|
|
79
|
-
[symbol('$')]: {
|
|
80
|
-
command: {
|
|
81
|
-
symbol: symbolCommands.erase,
|
|
82
|
-
},
|
|
83
|
-
nextState: haltState,
|
|
84
|
-
},
|
|
85
|
-
[ifOtherSymbol]: {
|
|
86
|
-
command: {
|
|
87
|
-
symbol: symbolCommands.erase,
|
|
88
|
-
movement: movements.right,
|
|
89
|
-
},
|
|
90
|
-
},
|
|
91
|
-
}, 'deleteNumberInternal');
|
|
92
|
-
const deleteNumber = new State({
|
|
93
|
-
[symbol('^10$')]: {
|
|
94
|
-
nextState: goToNumbersStart.withOverrodeHaltState(deleteNumberInternal),
|
|
95
|
-
},
|
|
96
|
-
[ifOtherSymbol]: {
|
|
97
|
-
nextState: haltState,
|
|
98
|
-
},
|
|
99
|
-
}, 'deleteNumber');
|
|
100
|
-
// invertNumber — 5 nodes
|
|
101
|
-
//
|
|
102
|
-
// Composition: go to '^', then sweep right flipping each bit until '$'.
|
|
103
|
-
// Same shape as deleteNumber (goToNumbersStart.withOverrodeHaltState(...)) but
|
|
104
|
-
// the inner state writes the complement instead of erasing.
|
|
105
|
-
const invertNumberGoToNumberWithInversion = new State({
|
|
106
|
-
[symbol('^')]: {
|
|
107
|
-
command: {
|
|
108
|
-
movement: movements.right,
|
|
109
|
-
},
|
|
110
|
-
},
|
|
111
|
-
[symbol('1')]: {
|
|
112
|
-
command: {
|
|
113
|
-
symbol: '0',
|
|
114
|
-
movement: movements.right,
|
|
115
|
-
},
|
|
116
|
-
},
|
|
117
|
-
[symbol('0')]: {
|
|
118
|
-
command: {
|
|
119
|
-
symbol: '1',
|
|
120
|
-
movement: movements.right,
|
|
121
|
-
},
|
|
122
|
-
},
|
|
123
|
-
[symbol('$')]: {
|
|
124
|
-
nextState: haltState,
|
|
125
|
-
},
|
|
126
|
-
}, 'invertNumberGoToNumberWithInversion');
|
|
127
|
-
const invertNumber = new State({
|
|
128
|
-
[symbol('^10$')]: {
|
|
129
|
-
nextState: goToNumbersStart.withOverrodeHaltState(invertNumberGoToNumberWithInversion),
|
|
130
|
-
},
|
|
131
|
-
[ifOtherSymbol]: {
|
|
132
|
-
nextState: haltState,
|
|
133
|
-
},
|
|
134
|
-
}, 'invertNumber');
|
|
135
|
-
// normalizeNumber — 7 nodes
|
|
136
|
-
//
|
|
137
|
-
// Strips leading zeros by erasing them and re-planting '^' just before the first
|
|
138
|
-
// '1' (or before '$' if the entire number was zero — preserving "0" as "^$").
|
|
139
|
-
// Composition: go to '^', then move-start sweeps right erasing '^' and leading
|
|
140
|
-
// '0's; on first '1' or '$' it backs up one cell and writes a fresh '^' there.
|
|
141
|
-
const normalizeNumberPutNewStartSymbol = new State({
|
|
142
|
-
[symbol(alphabet.blankSymbol)]: {
|
|
143
|
-
command: {
|
|
144
|
-
symbol: '^',
|
|
145
|
-
},
|
|
146
|
-
nextState: goToNumber,
|
|
147
|
-
},
|
|
148
|
-
}, 'normalizeNumberPutNewStartSymbol');
|
|
149
|
-
const normalizeNumberMoveNumberStart = new State({
|
|
150
|
-
[symbol('^0')]: {
|
|
151
|
-
command: {
|
|
152
|
-
symbol: symbolCommands.erase,
|
|
153
|
-
movement: movements.right,
|
|
154
|
-
},
|
|
155
|
-
},
|
|
156
|
-
[symbol('1$')]: {
|
|
157
|
-
command: {
|
|
158
|
-
movement: movements.left,
|
|
159
|
-
},
|
|
160
|
-
nextState: normalizeNumberPutNewStartSymbol,
|
|
161
|
-
},
|
|
162
|
-
}, 'normalizeNumberMoveNumberStart');
|
|
163
|
-
const normalizeNumber = new State({
|
|
164
|
-
[symbol('^10$')]: {
|
|
165
|
-
nextState: goToNumbersStart.withOverrodeHaltState(normalizeNumberMoveNumberStart),
|
|
166
|
-
},
|
|
167
|
-
[ifOtherSymbol]: {
|
|
168
|
-
nextState: haltState,
|
|
169
|
-
},
|
|
170
|
-
}, 'normalizeNumber');
|
|
171
|
-
// plusOne — 5 nodes
|
|
172
|
-
//
|
|
173
|
-
// Walk to '$', step left into the LSB, then carry from the LSB:
|
|
174
|
-
// 1 → 0 (carry continues left)
|
|
175
|
-
// 0 → 1, then fill any 1s to the right with 0s (already done by the chain) and halt at '$'
|
|
176
|
-
// ^ → 1 (carry overflows the MSB) — write 1, step into the new blank cell on the
|
|
177
|
-
// left, plant a fresh '^' there, then sweep right turning the old leading 1s
|
|
178
|
-
// into 0s. This is what plusOneAddNumberStart and plusOneFillZeros handle.
|
|
179
|
-
//
|
|
180
|
-
// The bare-alphabet variant in @turing-machine-js/library-binary-numbers-bare
|
|
181
|
-
// drops to 3 nodes for the same operation by skipping the '^' relocation.
|
|
182
|
-
const plusOneFillZeros = new State({
|
|
183
|
-
[symbol('1')]: {
|
|
184
|
-
command: {
|
|
185
|
-
symbol: '0',
|
|
186
|
-
movement: movements.right,
|
|
187
|
-
},
|
|
188
|
-
},
|
|
189
|
-
[symbol('$')]: {
|
|
190
|
-
nextState: haltState,
|
|
191
|
-
},
|
|
192
|
-
}, 'plusOneFillZeros');
|
|
193
|
-
const plusOneAddNumberStart = new State({
|
|
194
|
-
[symbol(alphabet.blankSymbol)]: {
|
|
195
|
-
command: {
|
|
196
|
-
symbol: '^',
|
|
197
|
-
movement: movements.right,
|
|
198
|
-
},
|
|
199
|
-
},
|
|
200
|
-
[symbol('1')]: {
|
|
201
|
-
command: {
|
|
202
|
-
movement: movements.right,
|
|
203
|
-
},
|
|
204
|
-
nextState: plusOneFillZeros,
|
|
205
|
-
},
|
|
206
|
-
}, 'plusOneAddNumberStart');
|
|
207
|
-
const plusOneCaryOne = new State({
|
|
208
|
-
[symbol('0')]: {
|
|
209
|
-
command: {
|
|
210
|
-
symbol: '1',
|
|
211
|
-
movement: movements.right,
|
|
212
|
-
},
|
|
213
|
-
nextState: plusOneFillZeros,
|
|
214
|
-
},
|
|
215
|
-
[symbol('1')]: {
|
|
216
|
-
command: {
|
|
217
|
-
movement: movements.left,
|
|
218
|
-
},
|
|
219
|
-
},
|
|
220
|
-
[symbol('^')]: {
|
|
221
|
-
command: {
|
|
222
|
-
symbol: '1',
|
|
223
|
-
movement: movements.left,
|
|
224
|
-
},
|
|
225
|
-
nextState: plusOneAddNumberStart,
|
|
226
|
-
},
|
|
227
|
-
}, 'plusOneCaryOne');
|
|
228
|
-
const plusOne = new State({
|
|
229
|
-
[symbol('^10')]: {
|
|
230
|
-
command: {
|
|
231
|
-
movement: movements.right,
|
|
232
|
-
},
|
|
233
|
-
},
|
|
234
|
-
[symbol('$')]: {
|
|
235
|
-
command: {
|
|
236
|
-
movement: movements.left,
|
|
237
|
-
},
|
|
238
|
-
nextState: plusOneCaryOne,
|
|
239
|
-
},
|
|
240
|
-
[ifOtherSymbol]: {
|
|
241
|
-
nextState: haltState,
|
|
242
|
-
},
|
|
243
|
-
}, 'plusOne');
|
|
244
|
-
// minusOne — 17 nodes (the largest in this library)
|
|
245
|
-
//
|
|
246
|
-
// Computes x − 1 via the two's-complement identity: x − 1 == ~(~x + 1)
|
|
247
|
-
// (every step is a state we already have), composed with three nested
|
|
248
|
-
// withOverrodeHaltState calls to chain invert → plusOne → invert → normalize.
|
|
249
|
-
//
|
|
250
|
-
// This is *deliberately* the heavy version. It exists side-by-side with
|
|
251
|
-
// minusOneFast (10 nodes, direct borrow) to make the cost of "compose existing
|
|
252
|
-
// pieces" vs "write a dedicated algorithm" visible. See ../states.md for the
|
|
253
|
-
// dotted onHalt edges that show the four-deep subroutine chain.
|
|
254
|
-
const minusOne = new State({
|
|
255
|
-
[symbol('^10')]: {
|
|
256
|
-
command: {
|
|
257
|
-
movement: movements.right,
|
|
258
|
-
},
|
|
259
|
-
},
|
|
260
|
-
[symbol('$')]: {
|
|
261
|
-
nextState: invertNumber
|
|
262
|
-
.withOverrodeHaltState(plusOne
|
|
263
|
-
.withOverrodeHaltState(invertNumber
|
|
264
|
-
.withOverrodeHaltState(normalizeNumber))),
|
|
265
|
-
},
|
|
266
|
-
[ifOtherSymbol]: {
|
|
267
|
-
nextState: haltState,
|
|
268
|
-
},
|
|
269
|
-
}, 'minusOne');
|
|
270
|
-
// minusOneFast — 10 nodes (direct borrow propagation)
|
|
271
|
-
//
|
|
272
|
-
// Walks left from the LSB: 0→1 keeps borrowing; 1→0 stops; ^ is underflow.
|
|
273
|
-
// Falls through to normalizeNumber to strip the leading zero introduced when the
|
|
274
|
-
// borrow chain reaches the MSB (e.g. ^1000$ - 1 = ^0111$ → ^111$).
|
|
275
|
-
//
|
|
276
|
-
// Same algorithm as minusOne in @turing-machine-js/library-binary-numbers-bare
|
|
277
|
-
// (which is 3 nodes there). The extra 7 nodes here are the cost of: scanning
|
|
278
|
-
// past '^' on entry, the goToNumberStart path and its withOverrodeHaltState
|
|
279
|
-
// wrapper for normalize, and normalizeNumber's own marker-relocation chain.
|
|
280
|
-
const minusOneFastBorrow = new State({
|
|
281
|
-
[symbol('1')]: {
|
|
282
|
-
command: {
|
|
283
|
-
symbol: '0',
|
|
284
|
-
},
|
|
285
|
-
nextState: haltState,
|
|
286
|
-
},
|
|
287
|
-
[symbol('0')]: {
|
|
288
|
-
command: {
|
|
289
|
-
symbol: '1',
|
|
290
|
-
movement: movements.left,
|
|
291
|
-
},
|
|
292
|
-
},
|
|
293
|
-
[symbol('^')]: {
|
|
294
|
-
nextState: haltState,
|
|
295
|
-
},
|
|
296
|
-
}, 'minusOneFastBorrow');
|
|
297
|
-
const minusOneFast = new State({
|
|
298
|
-
[symbol('^10')]: {
|
|
299
|
-
command: {
|
|
300
|
-
movement: movements.right,
|
|
301
|
-
},
|
|
302
|
-
},
|
|
303
|
-
[symbol('$')]: {
|
|
304
|
-
command: {
|
|
305
|
-
movement: movements.left,
|
|
306
|
-
},
|
|
307
|
-
nextState: minusOneFastBorrow.withOverrodeHaltState(normalizeNumber),
|
|
308
|
-
},
|
|
309
|
-
[ifOtherSymbol]: {
|
|
310
|
-
nextState: haltState,
|
|
311
|
-
},
|
|
312
|
-
}, 'minusOneFast');
|
|
313
|
-
function getTapeBlock() {
|
|
314
|
-
return tapeBlock.clone();
|
|
315
|
-
}
|
|
316
|
-
export default {
|
|
317
|
-
getTapeBlock,
|
|
318
|
-
states: {
|
|
319
|
-
goToNumber,
|
|
320
|
-
goToNextNumber,
|
|
321
|
-
goToPreviousNumber,
|
|
322
|
-
deleteNumber,
|
|
323
|
-
goToNumbersStart,
|
|
324
|
-
invertNumber,
|
|
325
|
-
normalizeNumber,
|
|
326
|
-
plusOne,
|
|
327
|
-
minusOne,
|
|
328
|
-
minusOneFast,
|
|
329
|
-
},
|
|
330
|
-
};
|